/*
* @(#)DocumentOperationManager.java
*
* Copyright (c) 2003 DCIVision Ltd
* All rights reserved.
*
* This software is the confidential and proprietary information of DCIVision
* Ltd ("Confidential Information").  You shall not disclose such Confidential
* Information and shall use it only in accordance with the terms of the license
* agreement you entered into with DCIVision Ltd.
*/
package com.dcivision.dms.core;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.dcivision.alert.bean.MtmUpdateAlertRecipient;
import com.dcivision.alert.bean.UpdateAlert;
import com.dcivision.alert.bean.UpdateAlertSystemLog;
import com.dcivision.alert.bean.UpdateAlertType;
import com.dcivision.alert.core.AdapterMaster;
import com.dcivision.alert.core.AlertManager;
import com.dcivision.alert.dao.MtmUpdateAlertRecipientDAObject;
import com.dcivision.alert.dao.UpdateAlertSystemLogDAObject;
import com.dcivision.alert.dao.UpdateAlertTypeDAObject;
import com.dcivision.audit.AuditTrailConstant;
import com.dcivision.audit.bean.AuditTrail;
import com.dcivision.audit.core.AuditTrailManager;
import com.dcivision.audit.dao.AuditTrailDAObject;
import com.dcivision.dms.DmsErrorConstant;
import com.dcivision.dms.DmsOperationConstant;
import com.dcivision.dms.bean.DmsArchive;
import com.dcivision.dms.bean.DmsArchiveDetail;
import com.dcivision.dms.bean.DmsContent;
import com.dcivision.dms.bean.DmsDefaultProfileSetting;
import com.dcivision.dms.bean.DmsDocument;
import com.dcivision.dms.bean.DmsDocumentDetail;
import com.dcivision.dms.bean.DmsDocumentIndex;
import com.dcivision.dms.bean.DmsDocumentIndexCache;
import com.dcivision.dms.bean.DmsLocMaster;
import com.dcivision.dms.bean.DmsObjectHomeFolder;
import com.dcivision.dms.bean.DmsRoot;
import com.dcivision.dms.bean.DmsSendEmail;
import com.dcivision.dms.bean.DmsValidation;
import com.dcivision.dms.bean.DmsVersion;
import com.dcivision.dms.bean.MtmDocumentRelationship;
import com.dcivision.dms.bean.MtmDocumentVersion;
import com.dcivision.dms.dao.DmsArchiveDetailDAObject;
import com.dcivision.dms.dao.DmsCheckoutHistoryDAObject;
import com.dcivision.dms.dao.DmsContentDAObject;
import com.dcivision.dms.dao.DmsDocumentDAObject;
import com.dcivision.dms.dao.DmsDocumentDetailDAObject;
import com.dcivision.dms.dao.DmsDocumentIndexCacheDAObject;
import com.dcivision.dms.dao.DmsDocumentIndexDAObject;
import com.dcivision.dms.dao.DmsLocMasterDAObject;
import com.dcivision.dms.dao.DmsObjectHomeFolderDAObject;
import com.dcivision.dms.dao.DmsRootDAObject;
import com.dcivision.dms.dao.DmsVersionDAObject;
import com.dcivision.dms.dao.MtmDocumentRelationshipDAObject;
import com.dcivision.dms.dao.MtmDocumentVersionDAObject;
import com.dcivision.forum.ForumOperationConstant;
import com.dcivision.forum.core.ForumManager;
import com.dcivision.framework.AdapterMasterFactory;
import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.AutoLabelGenerator;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.HTTPUtility;
import com.dcivision.framework.IDFactory;
import com.dcivision.framework.MessageResourcesFactory;
import com.dcivision.framework.PermissionManager;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.UserInfoFactory;
import com.dcivision.framework.Utility;
import com.dcivision.framework.bean.GenericAddress;
import com.dcivision.framework.bean.SysUserDefinedIndex;
import com.dcivision.framework.bean.SysUserDefinedIndexDetail;
import com.dcivision.framework.dao.SysUserDefinedIndexDAObject;
import com.dcivision.framework.dao.SysUserDefinedIndexDetailDAObject;
import com.dcivision.framework.notification.EmailDeliveryMessage;
import com.dcivision.framework.notification.NotificationWay;
import com.dcivision.framework.notification.NotificationWayFactory;
import com.dcivision.lucene.FieldNames;
import com.dcivision.lucene.IndexManager;
import com.dcivision.workflow.bean.MtmWorkflowProgressSystemObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressSystemObjectDAObject;

/**
 * <p>
 * Class Name: DocumentOperationManager.java
 * </p>
 * <p>
 * Description: The class mainly handle the dmsDocument operation process, like create, delete, etc.
 * </p>
 *
 * @author              Zoe Shum
 * @company             DCIVision Limited
 * @creation date       01/08/2003
 * @version             $Revision: 1.310.2.25 $
 */

public class DocumentOperationManager {

  public static final String REVISION = "$Revision: 1.310.2.25 $";

  protected Log log = LogFactory.getLog(this.getClass().getName());
  private SessionContainer sessionContainer = null;
  private Connection conn=null;

  private DmsDocumentNameConvertor documentNameConvertor = null;
  private DmsContentStoreHandler contentStoreHandler = null;
  private AutoLabelGenerator labelGenerator = null;

  /**
   *  Constructor - Creates a new instance of DocumentOperationManager
   */
  public DocumentOperationManager(SessionContainer sessionContainer, Connection conn) {
    this.sessionContainer = sessionContainer;
    this.conn = conn;
   }

  /**
   *  Release - To release the variable in instance of DocumentOperationManager
   */
  public void release () {
    this.sessionContainer = null;
    this.conn = null;
  }

  /**
   *  Method createDocument() - Create a new document in DMS
   *
   *  @param      dmsDocument              The object of DmsDocument to be created with detail information
   *  @param      data                     The (InputStream) type of document content.
   *  @return     DmsDocument              The (DmsDocument) of corresponding dmsDocument.
   *  @throws     ApplicationException     Throws when create operation fault.
   */
  public DmsDocument createDocument(DmsDocument dmsDocument, InputStream data) throws DuplicateNameException, ContentStoreException,
      ApplicationException {
    return createDocument(dmsDocument, data, true, null);
  }

  public DmsDocument createDocument(DmsDocument dmsDocument, InputStream data, boolean createFile) throws DuplicateNameException,
      ContentStoreException, EmptyContentException, ApplicationException {
    return createDocument(dmsDocument, data, createFile, null);
  }

  /**
   * Creates a new document in DMS <br>
   *
   * <Pre>
   *
   * This method is a series of operation to create the a document it includes 1. Create of dmsDocument 2. Create of
   * dmsVersion 3. Create of dmsContent 4. Create of the physical file content 5. Create of the user defined detail if
   * the document has 6. Create of audit log record 7. Create of the Index information on db storage and Lucence full
   * text storage 8. if there are update alert is set, update the update alert
   *
   * </Pre>
   *
   * @param dmsDocument  the dmsDocument object to be created
   * @param data         the inputStream data of the uploaded document
   * @param createFile   true if physical file is to be stored in ParaDoc file system
   * @param fullTextData InputStream of the fullText to be store in Lucene
   * @return the dmsDocument object after created
   * @throws DuplicateNameException
   * @throws ContentStoreException
   * @throws EmptyContentException
   * @throws ApplicationException
   *
   * <pre>
   * ApplicationException with the following message codes will be thrown
   * DmsErrorConstant.COMMON_FATAL_ERROR - Common fatal error
   * DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND - No physical file operation handle class found error
   * </pre>
   *
   * @see com.dcivision.dms.DmsErrorConstant
   * @see com.dcivision.dms.bean.DmsVersion
   * @see com.dcivision.dms.bean.DmsContent
   * @see com.dcivision.dms.core.DmsContentStoreHandler
   */
  public DmsDocument createDocument(DmsDocument dmsDocument, InputStream data, boolean createFile, InputStream fullTextData)
      throws DuplicateNameException, ContentStoreException, EmptyContentException, ApplicationException {
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
    DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);

    // check duplicate name of same level if config file defined -- Moved to DAO
    docValidateManager.checkHasPermissionOnObject(GlobalConstant.OBJECT_TYPE_DOCUMENT, dmsDocument.getParentID(), dmsDocument.getRootID(),
        "I");
    log.debug(".................................Has permission on target folder");
    // check if the uploaded file is empty content or does not exist.
    if (dmsDocument.getCreatePhysicalFile()){
      docValidateManager.checkDocumentIsEmptyContent(data);
    }

    //Check for available space
    if (createFile) {
      docValidateManager.checkStorageLimitAvailable(dmsDocument);
      log.debug(".................................Available space exists for current document");
    }

    List detailList = dmsDocument.getDocumentDetails();
    if (!Utility.isEmpty(detailList) && docValidateManager.validateUDFAutoGeneration((DmsDocumentDetail)detailList.get(0))) {
      log.debug("getting doc details ....... " +detailList.size());
      String targetField = SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_UDF_SUPPORT_AUTO_GENERATE);
      DmsDocumentDetail docDetail = (DmsDocumentDetail) detailList.get(0);
      dmsDocument = udfAutoGenerateValidation(dmsDocument, docDetail.getUserDefinedFieldID(), targetField);
    }

    if (!DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
      // Get the reference no.
      try {
        log.debug("Original Reference No: " + dmsDocument.getReferenceNo());
        ReferenceNoProcessor refNoProc = (ReferenceNoProcessor)Class.forName(
            SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_REFERENCE_NO_PROCESSOR_CLASS)).newInstance();
        String processedReferenceNo = refNoProc.generateReferenceNo(dmsDocument);
        dmsDocument.setReferenceNo(processedReferenceNo);
        log.debug("Processed Reference No: " + dmsDocument.getReferenceNo());
      } catch (Exception e) {
        log.error("Error when generating reference no.", e);
        throw new ApplicationException(DmsErrorConstant.COMMON_FATAL_ERROR, e);
      }
    }
    String tmpReminder = dmsDocument.getReminderType();
    if (!Utility.isEmpty(tmpReminder)){
      StringTokenizer sk = new StringTokenizer(dmsDocument.getReminderType(), ";", false);
      Integer reminderAmount = null;
      String reminderType = null;
      if (sk.hasMoreTokens()) {
        reminderAmount = TextUtility.parseIntegerObj(sk.nextToken());
      }
      if (sk.hasMoreTokens()) {
        reminderType = sk.nextToken();
      }
      dmsDocument.setReminderAmount(reminderAmount);
      dmsDocument.setReminderType(reminderType);
    }
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);

    DmsDocument newDmsDocument = null;

    //validate duplicated name (lee add try catch finally 06/11/29 EIP-539)
    docValidateManager.checkAndLockDuplicateNameCache(dmsDocument);
    newDmsDocument = (DmsDocument) dmsDocumentDAO.insertObject(dmsDocument);
    log.debug("document created " + newDmsDocument.getDocumentName() + newDmsDocument.getID() + newDmsDocument.getParentID()
        + newDmsDocument.getRootID());

    String convertedName = "";
    Integer contentID= IDFactory.getInstance().getNextSequence("DMS_CONTENT");
    Integer segmentNoInt = null;
    if (createFile) {
      //Create Physical Document
      //Create physical root directory & Content
      try {
        this.documentNameConvertor = (DmsDocumentNameConvertor) Class.forName(
            SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_NAME_CONVERTOR_CLASS)).newInstance();
      } catch (Exception e) {
        log.error("Name Convertor class not found.", e);
        throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
      }
      newDmsDocument.setVersionNumber("1"); //used to create the converted name

      //use the shortDocumentNameConvertor
      String  convertClassName=SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_NAME_CONVERTOR_CLASS);
      if(convertClassName.indexOf("ShortDocumentNameConvertor")>0){
        DmsDocument tempDmsDocument = new DmsDocument();
        tempDmsDocument.setID(contentID);
        convertedName = this.documentNameConvertor.encryptDocumentName(tempDmsDocument);
      }else{
        convertedName = this.documentNameConvertor.encryptDocumentName(newDmsDocument);
      }

      // create physical file
      // update by beyond for fix deadlock at 2007/03/21
      this.contentStoreHandler = dmsContentManager.writeDmsDocumentStoreContent(newDmsDocument,convertedName,data);
      segmentNoInt = (Integer)contentStoreHandler.getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
    }
    //Create Document Content
    DmsContent newContent = createDmsContent(newDmsDocument, convertedName, contentID, segmentNoInt);
    newDmsDocument.setContentID(newContent.getID());

    DmsVersion newDmsVersion = createDocumentVersion(newDmsDocument, newContent);
    newDmsDocument.setVersionID(newDmsVersion.getID());
    newDmsDocument.setVersionParentID(newDmsVersion.getParentID());
    newDmsDocument.setVersionLabel(newDmsVersion.getVersionLabel());
    newDmsDocument.setVersionNumber(newDmsVersion.getVersionNumber());
    log.debug("version and relation created");

    //Document Detail (UDF)
    List newDetailList = new ArrayList();
    setDocumentUDF(dmsDocument, detailList, newDmsDocument);
    newDetailList = newDmsDocument.getDocumentDetails();

    /* CreateDocument; check for alert notification */
    if (dmsDocument.getParentID().intValue() != 0) {
      DmsDocument parentDoc = (DmsDocument) dmsDocumentDAO.getObjectByID(dmsDocument.getParentID());
      try {
        AdapterMaster am = new AdapterMaster(sessionContainer, conn);
        am.call(UpdateAlert.DOCUMENT_TYPE, parentDoc.getID(), UpdateAlert.CREATE_ACTION, newDmsDocument.getDocumentName(), null, null,
            null, newDmsDocument.getID());
        am.release();
      } catch (Exception e) {
        log.error("Error when doing alert", e);
      }
    }

    // log down in audit trail
    if (createFile) {
      if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDmsDocument.getDocumentType()))) {
        AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
        auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDmsDocument, AuditTrailConstant.ACCESS_TYPE_CREATE, newDmsVersion
            .getVersionNumber());
        auditManager.release();
      }

      //Special handling for scanning doc, since the file ext will be TIF/PDF, but the data is TEXT
      if (dmsDocument.getScanDocumentForFullText()) {
        DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDmsDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_INSERT,
            DmsDocumentIndexCache.ACTION_TYPE_RUN_IMMEDIATELY, null);
        this.indexLUCENE(indexCache, newDmsDocument, newContent, fullTextData);
        if(!Utility.isEmpty(newDetailList)){
          this.modifyDbIndex('I',newDetailList,newDmsDocument.getID());
        }
      } else {
        DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDmsDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_INSERT,
            DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_PARAM, null);
        this.indexLUCENE(indexCache, newDmsDocument, newContent, fullTextData);
        if(!Utility.isEmpty(newDetailList)){
          this.modifyDbIndex('I',newDetailList,newDmsDocument.getID());
        }
      }
    } else {
      //Add By Jim.Zhou		2006/07/18		Bug	#5894
      if(DmsDocument.PAPER_DOC_TYPE.equals(newDmsDocument.getDocumentType())){
        if (sessionContainer.getUserRecordID() != null) {
          AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
          auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDmsDocument, AuditTrailConstant.ACCESS_TYPE_CREATE, newDmsVersion
              .getVersionNumber());
          auditManager.release();
        }
      }
      //Add End
      DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDmsDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_INSERT,
          DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_PARAM, null);
      this.indexLUCENE(indexCache, newDmsDocument, newContent, null);
      if(!Utility.isEmpty(newDetailList)){
        this.modifyDbIndex('I',newDetailList,newDmsDocument.getID());
      }
    }

    /* CreateDocument Reminder; setup reminder notification */
    if (!Utility.isEmpty(newDmsDocument.getReminderType())){
      UpdateAlert updateAlert = new UpdateAlert();
      updateAlert.setObjectType(UpdateAlert.DOCUMENT_TYPE);
      updateAlert.setObjectID(newDmsDocument.getID());
      AlertManager alertManager = new AlertManager(sessionContainer, conn);
      alertManager.newReminderAlert(updateAlert, UpdateAlert.DOCUMENT_TYPE, newDmsDocument.getID(), newDmsDocument);
      alertManager.release();
    }
    newDmsDocument.setReminderType(tmpReminder);  //used to setup the display method for reminder


    dmsDocumentDAO=null;
    docValidateManager.release();

    return newDmsDocument;
  }
  /**
   *
   * @param dmsDocument
   * @param docRetrievalManager
   * @param detailList
   * @param newDmsDocument
   * @param newDetailList
   * @throws ApplicationException
   */
  private void setDocumentUDF(DmsDocument dmsDocument, List detailList, DmsDocument newDmsDocument) throws ApplicationException {
    DmsDocumentDetail docDetail = null;
    DmsDocumentDetail newDocDetail = null;
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    List newDetailList = new ArrayList();

    if (!Utility.isEmpty(detailList)) {
      for (int i = 0; i < detailList.size(); i++) {
        docDetail = (DmsDocumentDetail) detailList.get(i);
        log.debug("      detail udf " + docDetail.getUserDefinedFieldID() + " udfdetailID = " + docDetail.getUserDefinedFieldDetailID()
            + " creating");
        log.debug("      detail fieldValue " + docDetail.getFieldValue() + " dateValue = " + docDetail.getDateValue() + " creating");
        docDetail.setDocumentID(newDmsDocument.getID());
        newDocDetail = this.createDocumentDetail(docDetail);
        newDetailList.add(newDocDetail);
      }
      List udfDetailList = docRetrievalManager.getUDFDetailList(newDocDetail.getUserDefinedFieldID());
      newDmsDocument.setUserDefinedFieldID(newDocDetail.getUserDefinedFieldID());
      newDmsDocument.setUdfDetailList(udfDetailList);
      newDmsDocument.setDocumentDetails(newDetailList);
      docRetrievalManager = null;
    }else if (dmsDocument.getUserDefinedFieldID() != null) {
      docDetail = new DmsDocumentDetail();
      docDetail.setDocumentID(newDmsDocument.getID());
      docDetail.setUserDefinedFieldID(dmsDocument.getUserDefinedFieldID());
      if (!Utility.isEmpty(docDetail.getFieldValue()) && docDetail.getFieldValue().length() > 255) {
        docDetail.setFieldValue(docDetail.getFieldValue().substring(0, 254));
      }
      newDocDetail = this.createDocumentDetail(docDetail);
      newDetailList.add(newDocDetail);
      log.debug("      detail udf " + docDetail.getUserDefinedFieldID() + " udfdetailID = " + docDetail.getUserDefinedFieldDetailID()
          + " creating");
      List udfDetailList = docRetrievalManager.getUDFDetailList(newDocDetail.getUserDefinedFieldID());
      newDmsDocument.setUserDefinedFieldID(newDocDetail.getUserDefinedFieldID());
      newDmsDocument.setUdfDetailList(udfDetailList);
      newDmsDocument.setDocumentDetails(newDetailList);
      docRetrievalManager = null;
    }
  }

  /**
   * create a content record for newDmsDocument
   * @param newDmsDocument
   * @param convertedName
   * @param contentID
   * @param segmentNoInt
   * @return
   * @throws ApplicationException
   */
  private DmsContent createDmsContent(DmsDocument newDmsDocument, String convertedName, Integer contentID, Integer segmentNoInt) throws ApplicationException {
    DmsContent newContent = new DmsContent();
    newContent.setID(contentID);
    newContent.setSegmentNO(segmentNoInt);
    newContent.setConvertedName(convertedName);
    String contentType = URLConnection.guessContentTypeFromName(newDmsDocument.getDocumentName());
    newContent.setContentType(contentType);
    String docExt = "";
    if (newDmsDocument.getDocumentName().lastIndexOf(".") > 0) {
      docExt = newDmsDocument.getDocumentName().substring(newDmsDocument.getDocumentName().lastIndexOf("."));
    }
    if (docExt != null && docExt.length() > 0) {
      docExt = docExt.substring(1).toUpperCase();
    }
    newContent.setExt(docExt);
    DmsContentDAObject dmsContentDAO = new DmsContentDAObject(sessionContainer, conn);
    newContent = (DmsContent) dmsContentDAO.insertObject(newContent);
    //newDmsDocument.setContentID(newContent.getID());
    dmsContentDAO = null;
    log.debug("content record created");
    return newContent;
  }

  /**
   * Updates the a document in DMS
   *
   * <Pre>
   *
   * The update mainly update the 1. the dmsDocument object 2. the dmsDocumentDetail object 3. Create the audit trail
   * update operation record 4. update the update alert
   *
   * </Pre>
    *
   * @param dmsDocument
   * @return the update dmsDocument object
   * @throws ApplicationException
   * @see com.dcivision.dms.bean.DmsDocumentDetail
    */

  public DmsDocument updateDocument(DmsDocument dmsDocument) throws ApplicationException {
    return this.updateDocument(dmsDocument, true);
  }


  /**
   * Updates the a document in DMS
   *
   * <Pre>
   *
   * The update mainly update the 1. the dmsDocument object 2. the dmsDocumentDetail object 3. Create the audit trail
   * update operation record 4. update the update alert
   *
   * </Pre>
    *
   * @param dmsDocument
   * @param updateAllFlag true if update all document related information, false only update the dmsDocument reminder.
   * @return the update dmsDocument object
   * @throws ApplicationException
   * @see com.dcivision.dms.bean.DmsDocumentDetail
    */

  public DmsDocument updateDocument(DmsDocument dmsDocument, boolean updateAllFlag) throws ApplicationException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    log.debug("item status = " + dmsDocument.getItemStatus());
    //Parse the reminder type and amount
    String tmpReminder = dmsDocument.getReminderType();
    Integer reminderAmount = null;
    String reminderType = null;
    if (!Utility.isEmpty(tmpReminder) && updateAllFlag) {
      StringTokenizer sk = new StringTokenizer(tmpReminder, ";", false);
      if (sk.hasMoreTokens()) {
        reminderAmount = TextUtility.parseIntegerObj(sk.nextToken());
      }
      if (sk.hasMoreTokens()) {
        reminderType = sk.nextToken();
      }
      dmsDocument.setReminderAmount(reminderAmount);
      dmsDocument.setReminderType(reminderType);
    }

    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsDocument newDocument = (DmsDocument)dmsDocumentDAO.updateObject(dmsDocument);
    if (updateAllFlag) {
      newDocument.setReminderType(tmpReminder);
      DmsVersion newVersion = this.updateDocumentVersion(dmsDocument, DmsOperationConstant.DMS_TOP_VERSION);

      //start of update doc details
      List detailList = dmsDocument.getDocumentDetails();
      List newDetailList = new ArrayList();
      DmsDocumentDetail docDetail = null;
      DmsDocumentDetail newDocDetail = null;

      if (!Utility.isEmpty(detailList)) {
        log.debug("detailList = " + detailList.size());
        for (int i = 0; i < detailList.size(); i++) {
          docDetail = (DmsDocumentDetail)detailList.get(i);
          DmsDocumentDetail orgDocDetail = docRetrievalManager.getDetailObjectByDocIDUDFDetailID(dmsDocument.getID(), docDetail
              .getUserDefinedFieldDetailID());
          if (orgDocDetail != null) {
            if(!Utility.isEmpty(docDetail.getFieldValue()) && docDetail.getFieldValue().length()>255){
              docDetail.setFieldValue(docDetail.getFieldValue().substring(0,254));
            }
            orgDocDetail.setFieldValue(docDetail.getFieldValue());
            orgDocDetail.setDateValue(docDetail.getDateValue());
            orgDocDetail.setNumericValue(docDetail.getNumericValue());
            newDocDetail = this.updateDocumentDetail(orgDocDetail);
          } else {
            if(!Utility.isEmpty(docDetail.getFieldValue()) && docDetail.getFieldValue().length()>255){
              docDetail.setFieldValue(docDetail.getFieldValue().substring(0,254));
            }
            docDetail.setDocumentID(newDocument.getID());
            newDocDetail = this.createDocumentDetail(docDetail);
          }
          newDetailList.add(newDocDetail);
        }
        if (newDocDetail != null) {
          List udfDetailList = docRetrievalManager.getUDFDetailList(newDocDetail.getUserDefinedFieldID());
          newDocument.setUserDefinedFieldID(newDocDetail.getUserDefinedFieldID());
          newDocument.setUdfDetailList(udfDetailList);
          newDocument.setDocumentDetails(newDetailList);
          log.debug("new doc detail list = " + newDetailList.size());
        }
      } //end of creating doc detail
      else if (dmsDocument.getUserDefinedFieldID() != null) {
        docDetail = new DmsDocumentDetail();
        docDetail.setDocumentID(newDocument.getID());
        docDetail.setUserDefinedFieldID(dmsDocument.getUserDefinedFieldID());
        if(!Utility.isEmpty(docDetail.getFieldValue()) && docDetail.getFieldValue().length()>255){
          docDetail.setFieldValue(docDetail.getFieldValue().substring(0,254));
        }
        newDocDetail = this.createDocumentDetail(docDetail);
        newDetailList.add(newDocDetail);

        List udfDetailList = docRetrievalManager.getUDFDetailList(newDocDetail.getUserDefinedFieldID());
        newDocument.setUserDefinedFieldID(newDocDetail.getUserDefinedFieldID());
        newDocument.setUdfDetailList(udfDetailList);
        newDocument.setDocumentDetails(newDetailList);
      }
      DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_UPDATE,
          DmsDocumentIndexCache.ACTION_TYPE_UPDATE_ALL, dmsDocument.getID());
      this.indexLUCENE(indexCache, dmsDocument, null, null);
      if(!Utility.isEmpty(newDetailList)){
      this.modifyDbIndex('U',newDetailList,newDocument.getID());
      }
      //audit create folder
      if (sessionContainer.getUserRecordID() != null && sessionContainer.getSessionID() != null
          && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDocument.getDocumentType()))) {
        AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
        auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDocument, AuditTrailConstant.ACCESS_TYPE_UPDATE, newVersion
            .getVersionNumber());
        auditManager.release();
      }
        /* CreateDocument Reminder; setup reminder notification */
      if (!Utility.isEmpty(newDocument.getReminderType())) {
        AlertManager alertManager = new AlertManager(sessionContainer, conn);
        alertManager.updateReminderAlert(UpdateAlert.DOCUMENT_TYPE, newDocument.getID(), newDocument);
        alertManager.release();
      }
      //if modify document status (contains restore deleted file,restore archive file,move file,modify index) then send alert

      DmsDocument parentDoc = (DmsDocument) dmsDocumentDAO.getObjectByID(dmsDocument.getParentID());
      AdapterMaster am = AdapterMasterFactory.getAdapterMaster(sessionContainer, conn);
      try {
        am.call(UpdateAlert.DOCUMENT_TYPE, parentDoc.getID(), UpdateAlert.UPDATE_ACTION, dmsDocument.getDocumentName(), null, null, null, dmsDocument.getID());
        am.call(UpdateAlert.DOCUMENT_TYPE, dmsDocument.getID(), UpdateAlert.UPDATE_ACTION, dmsDocument.getDocumentName(), null, null, null);
        if(docRetrievalManager.hasRelationship(dmsDocument.getID(),null)){
          alertRelationDoc(dmsDocument, am);
    }
        am.release();
      } catch (Exception e) {
        log.error(e, e);
      }
    }
    dmsDocumentDAO=null;
    docRetrievalManager.release();

    return(newDocument);
  }

  /**
   * if document is relationShip Doc then find the related document and send alert
   * @param dmsDocument
   * @param am
   * @throws ApplicationException
   */
  private void alertRelationDoc(DmsDocument dmsDocument, AdapterMaster am) throws ApplicationException {
    MtmDocumentRelationshipDAObject dmsMtmDocumentRelationshipDAO = new MtmDocumentRelationshipDAObject (sessionContainer, conn);
    AlertManager alertManager = new AlertManager(sessionContainer, conn);
    List relationList=dmsMtmDocumentRelationshipDAO.getListByIDRelationType(dmsDocument.getID(),null);
      List inRelationList=dmsMtmDocumentRelationshipDAO.getListByRelationIDRelationType(dmsDocument.getID(),null);
      List alertList=new ArrayList();
      if(!Utility.isEmpty(relationList)){
          for(int i=0;i<relationList.size();i++){
        alertList = alertManager.listUpdateAlertByObjectTypeObjectIDAndAction(UpdateAlert.DOCUMENT_TYPE,((MtmDocumentRelationship)relationList.get(i)).getDocumentID(),UpdateAlert.MODIFY_RELATED_DOC);
            if(!Utility.isEmpty(alertList)){
                am.call(UpdateAlert.DOCUMENT_TYPE,((MtmDocumentRelationship)relationList.get(i)).getDocumentID(),UpdateAlert.MODIFY_RELATED_DOC,dmsDocument.getDocumentName(),
            null,null,null,dmsDocument.getID());
             }
      }
     }
    if(!Utility.isEmpty(inRelationList)){
    for(int i=0;i<inRelationList.size();i++){
          alertList= alertManager.listUpdateAlertByObjectTypeObjectIDAndAction(UpdateAlert.DOCUMENT_TYPE,((MtmDocumentRelationship)inRelationList.get(i)).getRelatedDocumentID(),UpdateAlert.MODIFY_RELATED_DOC);
          if(!Utility.isEmpty(alertList)){
              am.call(UpdateAlert.DOCUMENT_TYPE,((MtmDocumentRelationship)inRelationList.get(i)).getRelatedDocumentID(),UpdateAlert.MODIFY_RELATED_DOC,dmsDocument.getDocumentName(),
          null,null,null,dmsDocument.getID());
          }
        }
    }
  }

  /**
   * Delete a document in dms and its related information, the delete operation is the Marked delete operation
    *
   * <pre>
   * The delete process include:
   * 1. delete of dmsDocument object i.e. update the record status to Inactive
   * 2. update the dmsDocument record status and index that store in DB and lucene
   * 3. delete of dmsGroupRoleFolder object
   * 3. Update the update alert if there are any other document with relationship with the delete document
   * 4. Create an audit trail of delete operation
   * 5. delete of other document related information
   * </pre>
   *
   * @param dmsDocument the deleted dmsDocument object
   * @return
   * @throws ApplicationException
   * @see com.dcivision.dms.core.DocumentOperationManager#deleteAllDocumentRelationship(DmsDocument dmsDocument)
    */
  public DmsDocument deleteDocument(DmsDocument dmsDocument) throws ApplicationException {
    DmsDocumentDetailDAObject dmsDocumentDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
    DmsContentDAObject dmsContainDAO = new DmsContentDAObject(sessionContainer, conn);
    MtmDocumentVersionDAObject dmsMtmDocumentVersionDAO = new MtmDocumentVersionDAObject(sessionContainer, conn);
    DmsCheckoutHistoryDAObject dmsCheckoutHistroyDAO = new DmsCheckoutHistoryDAObject(sessionContainer, conn);
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DmsObjectHomeFolderDAObject objectHomeFolderDAO  = new DmsObjectHomeFolderDAObject(sessionContainer, conn);

    DmsDocument originalDocument = dmsDocument;
    SysUserDefinedIndex sysUDFIndex = docRetrievalManager.getUserDefinedFieldByDocument(dmsDocument);


    if(!Utility.isEmpty(sysUDFIndex)){
        originalDocument.setUserDefinedFieldID(sysUDFIndex.getID());
    }
    originalDocument.setDocumentDetails(dmsDocumentDetailDAO.getListByDocumentID(originalDocument.getID()));


    //Delete target DmsDocument
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    dmsDocument = (DmsDocument)dmsDocumentDAO.deleteObject(dmsDocument);

    dmsDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_INACTIVE);
    originalDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_INACTIVE);

    //String [] deleteField = {IndexManager.INDEX_NAME_RECORD_STATUS};
    // this.indexDocument(dmsDocument ,null, GlobalConstant.OP_MODE_UPDATE,deleteField);
    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(originalDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_DELETE,
        DmsDocumentIndexCache.ACTION_TYPE_DELETE_SOFT, null);
    this.indexLUCENE(indexCache, null, null, null);

    /* Delete DmsDocumentDetails, DmsVersions, and DmsContent */
    /*
     * TODO List dmsDocumentDetailList = (List)dmsDocumentDetailDAO.getListByDocumentID(dmsDocument.getID()); for (int i =
     * 0; i < dmsDocumentDetailList.size(); i++) { dmsDocumentDetailDAO.deleteObjectByID( (
     * (DmsDocumentDetail)dmsDocumentDetailList.get(i)).getID()); } List dmsVersionList =
     * (List)dmsVersionDAO.getVersionsListByDocumentID(dmsDocument.getID(), "ASC"); for (int i = 0; i <
     * dmsVersionList.size(); i++) { DmsVersion version = (DmsVersion)dmsVersionList.get(i);
     * dmsContainDAO.deleteObjectByID(version.getContentID()); //delete content
     * dmsVersionDAO.deleteObjectByID(version.getID()); //delete version } List mtmDocumentVersion = (List)
     * dmsMtmDocumentVersionDAO.getListByDocumentID(dmsDocument.getID()); for (int i = 0; i < mtmDocumentVersion.size();
     * i++) { dmsMtmDocumentVersionDAO.deleteObjectByID( ( (MtmDocumentVersion)mtmDocumentVersion.get(i)).getID()); }
     * //checkoutHistory
     *
     * //Delete the fulltext index from document if (!DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
     * indexDocument(dmsDocument, null, GlobalConstant.OP_MODE_DELETE); }
*/

    //Soft Delete of the  DmsGroupRoleFolder
    if(DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())){

      List objectFolderList = objectHomeFolderDAO.getListByDocumentID(dmsDocument.getID());

      if(!Utility.isEmpty(objectFolderList)){
        for(int i=0;i<objectFolderList.size();i++){
          DmsObjectHomeFolder objectFolder = (DmsObjectHomeFolder) objectFolderList.get(i);

          objectFolder.setRecordStatus(GlobalConstant.RECORD_STATUS_INACTIVE);
          objectHomeFolderDAO.updateObjectHomeFolder(objectFolder);
        }
      }
    }



    //Audit trail; delete document
    if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(dmsDocument.getDocumentType()))) {
      AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, dmsDocument, AuditTrailConstant.ACCESS_TYPE_DELETE, null);
      auditManager.release();
    }
   // DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    /* Delete Document; check for alert notification */
    if (dmsDocument.getParentID().intValue() != 0) {
      DmsDocument parentDoc = (DmsDocument) dmsDocumentDAO.getObjectByID(dmsDocument.getParentID());
      try {
        AdapterMaster am = new AdapterMaster(sessionContainer, conn);
        am.call(UpdateAlert.DOCUMENT_TYPE, parentDoc.getID(), UpdateAlert.DELETE_ACTION, dmsDocument.getDocumentName(), null, null, null,
            dmsDocument.getID());
        am.call(UpdateAlert.DOCUMENT_TYPE, dmsDocument.getID(), UpdateAlert.DELETE_ACTION, dmsDocument.getDocumentName(), null, null, null);
        if(docRetrievalManager.hasRelationship(dmsDocument.getID(),null)){
          alertRelationDoc(dmsDocument, am);
          }
        am.release();
      } catch (Exception e) {
        log.error("Error when doing alert", e);
      }
    }

    /* Delete all the relationship exists in DMS*/
    deleteAllDocumentRelationship(dmsDocument);

    objectHomeFolderDAO  = null;
    dmsDocumentDetailDAO = null;
    dmsVersionDAO = null;
    dmsContainDAO = null;
    dmsMtmDocumentVersionDAO = null;
    dmsCheckoutHistroyDAO = null;

    return(dmsDocument);
  }

  /**
   * Deletes all existing document related information including discussion forum, update Alert, system logs and the
   * other document(s) that has the relation to the deleted document.
    *
   * @param dmsDocument the deleted dmsDocument object
   * @throws ApplicationException
    */
  public void deleteAllDocumentRelationship(DmsDocument dmsDocument) throws ApplicationException {
    boolean delAllRelationship = SystemParameterFactory
        .getSystemParameterBoolean(SystemParameterConstant.DMS_ENABLE_DOCUMENT_RELATIONSHIP_DELETION);
    if (delAllRelationship) {
      //AlertManager alertManager = new AlertManager(sessionContainer, conn);
      //Check and delete the alert and system logs
      // UpdateAlert updateAlert =
      // (UpdateAlert)alertManager.getUpdateAlertByObjectTypeObjectID(UpdateAlert.DOCUMENT_TYPE, dmsDocument.getID());
//      if (updateAlert!=null)
//        alertManager.deleteUpdateAlert(updateAlert, true);
//      alertManager.release();

      //check for discussion forum
      ForumManager forumManager = new ForumManager(sessionContainer, conn);
      List forumGroupDetailList = forumManager.getForumGroupDetailListByObjectTypeObjectID(
          ForumOperationConstant.FOURM_OBJECT_TYPE_DOCUMENT, dmsDocument.getID());
      forumManager.deleteForumGroupDetail(forumGroupDetailList);
      forumManager = null;

      //check for related document info and delete
      if (!DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())
          && !DmsDocument.DOCUMENT_TYPE.equals(dmsDocument.getDocumentType())
          && (!DmsDocument.COMPOUND_DOC_TYPE.equals(dmsDocument.getDocumentType()))
          && (!DmsDocument.PAPER_DOC_TYPE.equals(dmsDocument.getDocumentType()))) {
        MtmDocumentRelationshipDAObject mtmDocRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
        List relatedDocumentList = mtmDocRelationshipDAO.getAllRelatedDocumentListByTargetDocID(dmsDocument.getID());
        for (int i=0; i<relatedDocumentList.size(); i++){
          mtmDocRelationshipDAO.deleteObjectByID(((MtmDocumentRelationship)relatedDocumentList.get(i)).getID());
        }
        mtmDocRelationshipDAO=null;
      }

    }
  }

  /**
  * Restores the deleted document and retores the document related information
    *
  * <PRE>
   *
  * This method is for the recyle bin to restore the delete document.
  *
   * If the the delete document's parent document (folder, compound or paper document) is also delete, restore of the
   * delete document will also restore its parent document.
  *
   * if the delete document is the parent document of other document(s) i.e. the deleted document is folder, compound or
   * paper document, restore of this delete document will restore its sub document(s) too.
  *
   * Restore process include: 1. restore of the dmsDocument, update the record status back to Active 2. restore the
   * DmsObjectHomeFolder object corresponding to the dmsDocument object, update the record status to active
  *
  * </PRE>
  *
  * @param dmsDocument          the deletd dmsDocument object to be restored
  * @param restoreOtherChilds   true if it is need to restore its sub document(s)
  * @return the restored DmsDocument object
  * @throws ApplicationException
  * @see com.dcivision.dms.bean.DmsObjectHomeFolder
    */
  public DmsDocument restoreDocument(DmsDocument dmsDocument, boolean restoreOtherChilds) throws ApplicationException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);

//    DmsDocumentDetailDAObject dmsDocumentDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
//    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
//    DmsContentDAObject dmsContainDAO = new DmsContentDAObject(sessionContainer, conn);
//    MtmDocumentVersionDAObject dmsMtmDocumentVersionDAO = new MtmDocumentVersionDAObject(sessionContainer, conn);
//    DmsCheckoutHistoryDAObject dmsCheckoutHistroyDAO = new DmsCheckoutHistoryDAObject(sessionContainer, conn);
    DmsObjectHomeFolderDAObject objectHomeFolderDAO  = new DmsObjectHomeFolderDAObject(sessionContainer, conn);

    //restore target DmsDocument
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    //check it is reference document or general document
    DmsRootDAObject dmsRootDAO = new DmsRootDAObject(sessionContainer, conn);

    String cacheKey = DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType()) ? (dmsDocument.getParentID() + "::"
        + DmsDocument.DOCUMENT_LINK + "::" + dmsDocument.getDocumentName()) : (dmsDocument.getParentID() + "::" + dmsDocument
        .getDocumentName());

    //validate duplicated name (lee add try catch finally 06/11/29 EIP-539)
    docValidateManager.checkAndLockDuplicateNameCache(dmsDocument);

    if(!Utility.isEmpty(dmsDocument.getItemSize())){
      if ((DmsDocument.DOCUMENT_TYPE.equals(dmsDocument.getDocumentType()))
          && (DmsVersion.EXCLUSIVE_LOCK.equals(dmsDocument.getItemStatus())) && (dmsDocument.getItemSize().intValue() == 0)) {
            dmsDocument.setRecordStatus(DmsOperationConstant.DMS_RECORD_EMPTY);
      }else{
        dmsDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
      }
    }else{
      dmsDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
    }


    //dmsDocument.setUdfDetailList(docRetrievalManager.getDocumentDetailListActiveInactive(dmsDocument.getID()));
    dmsDocument = (DmsDocument)dmsDocumentDAO.updateObject(dmsDocument);

    //restore deleted file is considered to update operation so send alert
    AdapterMaster am = new AdapterMaster(sessionContainer, conn);
    am.call(UpdateAlert.DOCUMENT_TYPE, dmsDocument.getID(), UpdateAlert.UPDATE_ACTION, dmsDocument.getDocumentName(),
        null, null, null, dmsDocument.getID());
    am.release();

    //if the document is root,need restore root record also
    if(dmsDocument.getParentID().intValue() == 0){
        DmsRoot dmsRoot = (DmsRoot)dmsRootDAO.getObjectByIDIgnoreRecordStatus(dmsDocument.getRootID());
        dmsRoot.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
        dmsRootDAO.updateObject(dmsRoot);
    }

    //String [] restoreField = {IndexManager.INDEX_NAME_RECORD_STATUS};
    SysUserDefinedIndex sysUDFIndex = docRetrievalManager.getUserDefinedFieldByDocument(dmsDocument);

    if(!Utility.isEmpty(sysUDFIndex)){
      dmsDocument.setUserDefinedFieldID(sysUDFIndex.getID());
    }
    dmsDocument.setDocumentDetails(docRetrievalManager.getDocumentDetailListActiveInactive(dmsDocument.getID()));

    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(dmsDocument.getID(),DmsDocumentIndexCache.ACTION_MODE_RESTORE);
    this.indexLUCENE(indexCache, dmsDocument, null, null);

    //restore  DmsGroupRoleFolder
    if(DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())){
      List objectFolderList = objectHomeFolderDAO.getInactiveListByDocumentID(dmsDocument.getID());
        if(!Utility.isEmpty(objectFolderList)){
          for(int i=0;i<objectFolderList.size();i++){
             DmsObjectHomeFolder objectFolder = (DmsObjectHomeFolder) objectFolderList.get(i);
             objectFolder.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
             List existlist= new ArrayList();
             if(DmsObjectHomeFolder.MEMBER_TYPE_GROUP.equals(objectFolder.getMemberType())){
               existlist=objectHomeFolderDAO.getByMemberIDDocumentID(objectFolder.getMemberID(),DmsObjectHomeFolder.MEMBER_TYPE_GROUP);
             }else if(DmsObjectHomeFolder.MEMBER_TYPE_ROLE.equals(objectFolder.getMemberType())){
               existlist=objectHomeFolderDAO.getByMemberIDDocumentID(objectFolder.getMemberID(),DmsObjectHomeFolder.MEMBER_TYPE_ROLE);
             }

             if(Utility.isEmpty(existlist)){
               objectHomeFolderDAO.updateObjectHomeFolder(objectFolder);
             }

           }
         }
     }

    //restore folder/compound inactive parent document recursively
    //for restoring document folder upward, the other same level sibling will not restore,
    //only parent folder /compound doc will be restore..
    DmsDocument parentDocument = null;
    parentDocument = (DmsDocument)dmsDocumentDAO.getInactiveByID(dmsDocument.getParentID());
    if(parentDocument!=null){
      this.restoreDocument(parentDocument,false);
    }



    //  restore folder/compound sub document recursively
      if(restoreOtherChilds){
      if ((DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType()))
          || (DmsDocument.COMPOUND_DOC_TYPE.equals(dmsDocument.getDocumentType()))) {
          List tmpDmsDocumentList = new ArrayList();

          tmpDmsDocumentList=docRetrievalManager.getInactiveDocumentListByParentIDRootID(dmsDocument.getID(),dmsDocument.getRootID());
          tmpDmsDocumentList.addAll(docRetrievalManager.getDocumentListByParentIDRootID(dmsDocument.getID(),dmsDocument.getRootID()));

          for(int i=0;i<tmpDmsDocumentList.size();i++){
            DmsDocument tmpDmsDocument =(DmsDocument) tmpDmsDocumentList.get(i);
             this.restoreDocument(tmpDmsDocument, true);
          }
        }
    }


    /* Delete DmsDocumentDetails, DmsVersions, and DmsContent */
    /*
     * TODO List dmsDocumentDetailList = (List)dmsDocumentDetailDAO.getListByDocumentID(dmsDocument.getID(),
     * GlobalConstant.RECORD_STATUS_INACTIVE);
     *
     * for (int i = 0; i < dmsDocumentDetailList.size(); i++) { DmsDocumentDetail documentDetail =
     * (DmsDocumentDetail)dmsDocumentDetailList.get(i);
     * documentDetail.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
     * dmsDocumentDetailDAO.updateObject(documentDetail); } List dmsVersionList =
     * (List)dmsVersionDAO.getVersionsListByDocumentID(dmsDocument.getID(), "ASC",
     * GlobalConstant.RECORD_STATUS_INACTIVE); for (int i = 0; i < dmsVersionList.size(); i++) { DmsVersion version =
     * (DmsVersion)dmsVersionList.get(i); version.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
     * dmsVersionDAO.updateObject(version); //restore version
     *
     * DmsContent content = (DmsContent)dmsContainDAO.getObjectByID(version.getContentID());
     * content.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE); dmsContainDAO.updateObject(content); //restore
     * content
     *  } List mtmDocumentVersion = (List) dmsMtmDocumentVersionDAO.getListByDocumentID(dmsDocument.getID(),
     * GlobalConstant.RECORD_STATUS_INACTIVE); for (int i = 0; i < mtmDocumentVersion.size(); i++) { MtmDocumentVersion
     * documentVersion = (MtmDocumentVersion)mtmDocumentVersion.get(i);
     * documentVersion.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
     * dmsMtmDocumentVersionDAO.updateObject(documentVersion); } //checkoutHistory
*/
    /*
     * //Delete the fulltext index from document if (!DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
     * indexDocument(dmsDocument, null, GlobalConstant.OP_MODE_DELETE); }
     *
     * //Audit trail; delete document if (sessionContainer.getUserRecordID() != null) { AuditTrailManager auditManager =
     * new AuditTrailManager(sessionContainer, conn); auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT,
     * dmsDocument, AuditTrailConstant.ACCESS_TYPE_DELETE, null); auditManager.release(); }
*/

    /* Delete all the relationship exists in DMS*/
 //   deleteAllDocumentRelationship(dmsDocument);
    objectHomeFolderDAO = null;
//    dmsDocumentDetailDAO = null;
//    dmsVersionDAO = null;
//    dmsContainDAO = null;
//    dmsMtmDocumentVersionDAO = null;
//    dmsCheckoutHistroyDAO = null;

    return(dmsDocument);
  }

  /**
  * Restores the deleted document and retores the document related information 
  *
  * <PRE>
  * 
  * This method is for the recyle bin to restore the delete document.
  * 
  * If the the delete document's parent document (folder, compound or paper document) is also delete, restore of the
  * delete document will also restore its parent document.
  * 
  * if the delete document is the parent document of other document(s) i.e. the deleted document is folder, compound or
  * paper document, restore of this delete document will restore its sub document(s) too.
  * 
  * Restore process include: 1. restore of the dmsDocument, update the record status back to Active 2. restore the
  * DmsObjectHomeFolder object corresponding to the dmsDocument object, update the record status to active
  * 
  * </PRE>
  * 
  * @param dmsDocument          the deletd dmsDocument object to be restored
  * @param restoreOtherChilds   true if it is need to restore its sub document(s)
  * @param restoreShortcut      true if it is need to restore its shortcut(s)
  * @return the restored DmsDocument object
  * @throws ApplicationException
  * @see com.dcivision.dms.bean.DmsObjectHomeFolder
  */
  public DmsDocument restoreDocument(DmsDocument dmsDocument, boolean restoreOtherChilds, boolean restoreShortcut) throws ApplicationException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);

    DmsObjectHomeFolderDAObject objectHomeFolderDAO = new DmsObjectHomeFolderDAObject(sessionContainer, conn);

    MtmDocumentRelationshipDAObject mtmDocumentRelationshipDAObject = new MtmDocumentRelationshipDAObject(sessionContainer, conn);

    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);

    DmsRootDAObject dmsRootDAO = new DmsRootDAObject(sessionContainer, conn);

    String cacheKey = DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType()) ? (dmsDocument.getParentID() + "::"
        + DmsDocument.DOCUMENT_LINK + "::" + dmsDocument.getDocumentName()) : (dmsDocument.getParentID() + "::" + dmsDocument
        .getDocumentName());

    dmsDocument = docRetrievalManager.getDocument(dmsDocument.getID());
    if( GlobalConstant.RECORD_STATUS_ACTIVE.equals(dmsDocument.getRecordStatus()) ) {
      return dmsDocument;
    }
    
    docValidateManager.checkAndLockDuplicateNameCache(dmsDocument);

    if (!Utility.isEmpty(dmsDocument.getItemSize())) {
      if ((DmsDocument.DOCUMENT_TYPE.equals(dmsDocument.getDocumentType()))
          && (DmsVersion.EXCLUSIVE_LOCK.equals(dmsDocument.getItemStatus())) && (dmsDocument.getItemSize().intValue() == 0)) {
        dmsDocument.setRecordStatus(DmsOperationConstant.DMS_RECORD_EMPTY);
      } else {
        dmsDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
      }
    } else {
      dmsDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
    }
    
    //check rootid
    if (!Utility.isEmpty(dmsDocument.getItemSize()) && dmsDocument.getParentID().intValue() != 0) {
      DmsDocument pDocument = (DmsDocument)dmsDocumentDAO.getDocumentByID(dmsDocument.getParentID(), null);
      if (!Utility.isEmpty(pDocument)){
        dmsDocument.setRootID(pDocument.getRootID());
      }
    }

    dmsDocument = (DmsDocument) dmsDocumentDAO.updateObject(dmsDocument);
    
    //restore link's relationship
    if (DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())){
      List relationshipList = new ArrayList();
      List indirectRelationDocumentList = new ArrayList();
      MtmDocumentRelationship relationshipObj = new MtmDocumentRelationship();
      MtmDocumentRelationshipDAObject dmsMtmDocumentRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
      relationshipList = dmsMtmDocumentRelationshipDAO.getInactiveListByID(dmsDocument.getID(),null,GlobalConstant.RECORD_STATUS_INACTIVE);
      indirectRelationDocumentList = dmsMtmDocumentRelationshipDAO.getInactiveListByRelationID(dmsDocument.getID(),null,GlobalConstant.RECORD_STATUS_INACTIVE);
      if (relationshipList.size() > 0) {
        List idList = new ArrayList();
        for (int n = 0; n < relationshipList.size(); n++) {
          relationshipObj = (MtmDocumentRelationship) relationshipList.get(n);
          idList.add(relationshipObj.getID());
        }
        dmsMtmDocumentRelationshipDAO.updateListRecordStatus(idList);
      }
      if (indirectRelationDocumentList.size() > 0) {
        List idList = new ArrayList();
        for (int n = 0; n < indirectRelationDocumentList.size(); n++) {
          relationshipObj = (MtmDocumentRelationship) indirectRelationDocumentList.get(n);
          idList.add(relationshipObj.getID());
        }
        dmsMtmDocumentRelationshipDAO.updateListRecordStatus(idList);
      }
    }
    
    //resotre shortcut
    if (restoreShortcut) {
      List relationshipList = new ArrayList();
      List indirectRelationDocumentList = new ArrayList();
      MtmDocumentRelationship relationshipObj = new MtmDocumentRelationship();MtmDocumentRelationshipDAObject dmsMtmDocumentRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
      
      List tmpRelationshipList = mtmDocumentRelationshipDAObject.getInactiveListByID(dmsDocument.getID(),DmsDocument.DOCUMENT_LINK,GlobalConstant.RECORD_STATUS_INACTIVE);
      if (!tmpRelationshipList.isEmpty()) {
        for (int j = 0 ; j < tmpRelationshipList.size(); j++ ) {
          MtmDocumentRelationship tmpRelationship = (MtmDocumentRelationship)tmpRelationshipList.get(j);
          if (DmsDocument.DOCUMENT_LINK.equals(tmpRelationship.getRelationshipType())) {
            DmsDocument tmpShortcutDoc = docRetrievalManager.getDocument(tmpRelationship.getRelatedDocumentID());
            if (sessionContainer.getUserRecordID().equals(tmpShortcutDoc.getUpdaterID())) {
              relationshipList = dmsMtmDocumentRelationshipDAO.getInactiveListByID(dmsDocument.getID(),null,GlobalConstant.RECORD_STATUS_INACTIVE);
              indirectRelationDocumentList = dmsMtmDocumentRelationshipDAO.getInactiveListByRelationID(dmsDocument.getID(),null,GlobalConstant.RECORD_STATUS_INACTIVE);
              if (relationshipList.size() > 0) {
                List idList = new ArrayList();
                for (int n = 0; n < relationshipList.size(); n++) {
                  relationshipObj = (MtmDocumentRelationship) relationshipList.get(n);
                  idList.add(relationshipObj.getID());
                }
                dmsMtmDocumentRelationshipDAO.updateListRecordStatus(idList);
              }
              if (indirectRelationDocumentList.size() > 0) {
                List idList = new ArrayList();
                for (int n = 0; n < indirectRelationDocumentList.size(); n++) {
                  relationshipObj = (MtmDocumentRelationship) indirectRelationDocumentList.get(n);
                  idList.add(relationshipObj.getID());
                }
                dmsMtmDocumentRelationshipDAO.updateListRecordStatus(idList);
              }
              restoreDocument(tmpShortcutDoc, restoreOtherChilds, restoreShortcut);            
            }           
          }
        }
      }
    }
    
    //restore deleted file is considered to update operation so send alert 
    AdapterMaster am = new AdapterMaster(sessionContainer, conn);
    am.call(UpdateAlert.DOCUMENT_TYPE, dmsDocument.getID(), UpdateAlert.UPDATE_ACTION, dmsDocument.getDocumentName(),
        null, null, null, dmsDocument.getID());
    am.release();
    
    // if the document is root,need restore root record also
    if (dmsDocument.getParentID().intValue() == 0) {
      DmsRoot dmsRoot = (DmsRoot) dmsRootDAO.getObjectByIDIgnoreRecordStatus(dmsDocument.getRootID());
      dmsRoot.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
      dmsRootDAO.updateObject(dmsRoot);
    }

    SysUserDefinedIndex sysUDFIndex = docRetrievalManager.getUserDefinedFieldByDocument(dmsDocument);

    if (!Utility.isEmpty(sysUDFIndex)) {
      dmsDocument.setUserDefinedFieldID(sysUDFIndex.getID());
    }
    dmsDocument.setDocumentDetails(docRetrievalManager.getDocumentDetailListActiveInactive(dmsDocument.getID()));

    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(dmsDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_RESTORE);
    this.indexLUCENE(indexCache, dmsDocument, null, null);

    // restore DmsGroupRoleFolder
    if (DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())) {
      List objectFolderList = objectHomeFolderDAO.getInactiveListByDocumentID(dmsDocument.getID());
      if (!Utility.isEmpty(objectFolderList)) {
        for (int i = 0; i < objectFolderList.size(); i++) {
          DmsObjectHomeFolder objectFolder = (DmsObjectHomeFolder) objectFolderList.get(i);
          objectFolder.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
          List existlist = new ArrayList();
          if (DmsObjectHomeFolder.MEMBER_TYPE_GROUP.equals(objectFolder.getMemberType())) {
            existlist = objectHomeFolderDAO.getByMemberIDDocumentID(objectFolder.getMemberID(), DmsObjectHomeFolder.MEMBER_TYPE_GROUP);
          } else if (DmsObjectHomeFolder.MEMBER_TYPE_ROLE.equals(objectFolder.getMemberType())) {
            existlist = objectHomeFolderDAO.getByMemberIDDocumentID(objectFolder.getMemberID(), DmsObjectHomeFolder.MEMBER_TYPE_ROLE);
          }

          if (Utility.isEmpty(existlist)) {
            objectHomeFolderDAO.updateObjectHomeFolder(objectFolder);
          }

        }
      }
    }

    // restore folder/compound inactive parent document recursively
    // for restoring document folder upward, the other same level sibling will not restore,
    // only parent folder /compound doc will be restore..
    DmsDocument parentDocument = null;
    parentDocument = (DmsDocument) dmsDocumentDAO.getInactiveByID(dmsDocument.getParentID());
    if (parentDocument != null) {
      this.restoreDocument(parentDocument, false, restoreShortcut);
    }

    // restore folder/compound sub document recursively
    if (restoreOtherChilds) {
      if ((DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType()))
          || (DmsDocument.COMPOUND_DOC_TYPE.equals(dmsDocument.getDocumentType()))) {
        List tmpDmsDocumentList = new ArrayList();

        tmpDmsDocumentList = docRetrievalManager.getInactiveDocumentListByParentIDRootID(dmsDocument.getID(), dmsDocument.getRootID());
        tmpDmsDocumentList.addAll(docRetrievalManager.getDocumentListByParentIDRootID(dmsDocument.getID(), dmsDocument.getRootID()));

        for (int i = 0; i < tmpDmsDocumentList.size(); i++) {
          DmsDocument tmpDmsDocument = (DmsDocument) tmpDmsDocumentList.get(i);
          this.restoreDocument(tmpDmsDocument, true, restoreShortcut);
        }
      }
    }

    objectHomeFolderDAO = null;

    return (dmsDocument);
  }

  /**
   * Delete the dmsDocument and its related information permanently
   *
   * <PRE>
   *
   * This method is mainly for recycle bin to remove the deleted document permanently
   *
   * if the hard deleted document is parent of other document, its sub documents also deleted permanently
   *
   * The hard delete process include : 1. hard delete of the dmsDocument object 2. hard delete of the dmsDocument detail
   * 3. hard delete of the dmdDocument index 4. hard delete of the version 5. Remove any existing relation to other
   * document(s) 6. hard delete of archive information 7. hard delete of corresponding DmsObjectHomeFolder object 8.
   * Remove the lucene index of the hard delete document 9.
   *
   * </PRE>
   *
   * @param dmsDocument
   * @throws ApplicationException
   */
  public void hardDeleteDocument(DmsDocument dmsDocument) throws ApplicationException{
      DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
      DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
      RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);
      DmsDocumentDAObject dmsDocumentDAO  = new DmsDocumentDAObject(sessionContainer, conn);
      DmsDocumentDetailDAObject dmsDocumentDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
      DmsDocumentIndexDAObject dmsDocumentIndexDAO = new DmsDocumentIndexDAObject(sessionContainer, conn);
      DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
      DmsContentDAObject dmsContentDAO = new DmsContentDAObject(sessionContainer, conn);
//    DmsRootDAObject dmsRootDAO = new DmsRootDAObject(sessionContainer, conn);
      DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);


      MtmDocumentVersionDAObject dmsMtmDocumentVersionDAO = new MtmDocumentVersionDAObject(sessionContainer, conn);
      DmsCheckoutHistoryDAObject dmsCheckoutHistoryDAO = new DmsCheckoutHistoryDAObject(sessionContainer, conn);
      MtmDocumentRelationshipDAObject mtmDocRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
      DmsArchiveDetailDAObject dmsArchiveDetailDAO = new DmsArchiveDetailDAObject(sessionContainer, conn);
      DmsObjectHomeFolderDAObject objectHomeFolderDAO  = new DmsObjectHomeFolderDAObject(sessionContainer, conn);

      List documentVersionList = new ArrayList();
      documentVersionList = docRetrievalManager.getVersionListByDocumentID(dmsDocument.getID());
      //DmsRoot dmsRoot =(DmsRoot) rootRetrievalManager.getRootObject(dmsDocument.getRootID());
//    DmsRoot dmsRoot = (DmsRoot) dmsRootDAO.getObjectByIDIgnoreRecordStatus(dmsDocument.getRootID());


    //remove folder/compound sub document recursively
    if ((DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType()))
        || (DmsDocument.COMPOUND_DOC_TYPE.equals(dmsDocument.getDocumentType()))
        || (DmsDocument.PAPER_DOC_TYPE.equals(dmsDocument.getDocumentType()))) {
      List tmpDmsDocumentList = new ArrayList();

      //if folder is inactive (deleted), all its child doc is inactive, but
      //if for restoring of sub document, its status will change to active,
      //this approach will also delete such document
      tmpDmsDocumentList=docRetrievalManager.getInactiveDocumentListByParentIDRootID(dmsDocument.getID(),dmsDocument.getRootID());
      tmpDmsDocumentList.addAll(docRetrievalManager.getDocumentListByParentIDRootID(dmsDocument.getID(),dmsDocument.getRootID()));
      for(int i=0;i<tmpDmsDocumentList.size();i++){
        DmsDocument tmpDmsDocument =(DmsDocument) tmpDmsDocumentList.get(i);

        this.hardDeleteDocument(tmpDmsDocument);
       }
    }


    //hard delete the document record
    dmsDocumentDAO.hardDelete(dmsDocument);

    //hard delete document detail
    dmsDocumentDetailDAO.deleteByDocumentID(dmsDocument.getID());

    //hard delete document index
    dmsDocumentIndexDAO.deleteByDocID(dmsDocument.getID());

    //hard delete version
    dmsVersionDAO.deleteByDocumentID(dmsDocument.getID());

    //hard delete of MtmDocumentVersion
    dmsMtmDocumentVersionDAO.deleteByDocID(dmsDocument.getID());

    //hard delete of checkout history
    dmsCheckoutHistoryDAO.deleteByDocID(dmsDocument.getID());

    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(dmsDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_DELETE,
        DmsDocumentIndexCache.ACTION_TYPE_DELETE_HARD, null);
    this.indexLUCENE(indexCache, dmsDocument, null, null);


   //remove all shortcut
   if(!DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())){
     List shortcutDocList = docRetrievalManager.getInactiveActiveRelatedDocument(dmsDocument.getID(),DmsDocument.DOCUMENT_LINK);
     if(!Utility.isEmpty(shortcutDocList)){
       for(int i=0;i<shortcutDocList.size();i++){
         DmsDocument shortcutDoc = (DmsDocument)shortcutDocList.get(i);
         if (!docRetrievalManager.checkDocIsHardDeleted(shortcutDoc.getID())){
           this.hardDeleteDocument(shortcutDoc);
         }
       }
     }
   }

    //remove relationship
    //check for related document info and delete
    //if (!DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())) {
      mtmDocRelationshipDAO.deleteDirectIndirectRelationshipByID(dmsDocument.getID());

  //  }


  // remove the archive detail information
  dmsArchiveDetailDAO.deleteByDocumentID(dmsDocument.getID());


  //remove  DmsGroupRoleFolder
  if(DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())){
    List objectFolderList = objectHomeFolderDAO.getInactiveListByDocumentID(dmsDocument.getID());

    if(!Utility.isEmpty(objectFolderList)){
      for(int i=0;i<objectFolderList.size();i++){
        DmsObjectHomeFolder objectFolder = (DmsObjectHomeFolder) objectFolderList.get(i);

        objectHomeFolderDAO.deleteByID(objectFolder.getID());
      }
    }
   }

    //remove full text index
    //if (!DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
      //indexDocument(dmsDocument, null, GlobalConstant.OP_MODE_DELETE);
    //}



    //remove the alert message
    AlertManager alertManager = new AlertManager(sessionContainer, conn);
    UpdateAlertSystemLogDAObject updateAlertSystemLogDAO = new UpdateAlertSystemLogDAObject(sessionContainer,conn);
    //Check and delete the alert and system logs
    UpdateAlert updateAlert = alertManager.getUpdateAlertByObjectTypeObjectIDRecordStatus(UpdateAlert.DOCUMENT_TYPE, dmsDocument.getID(),
        null);
    if (updateAlert!=null){
      alertManager.hardDeleteUpdateAlert(updateAlert, true);
    }
    updateAlertSystemLogDAO.hardDeleteByRefObjectID(dmsDocument.getID());
    alertManager.release();

    //remove the forum
    //check for discussion forum
    ForumManager forumManager = new ForumManager(sessionContainer, conn);
    List forumGroupDetailList = forumManager.getInactiveForumGroupDetailListByObjectTypeObjectID(
        ForumOperationConstant.FOURM_OBJECT_TYPE_DOCUMENT, dmsDocument.getID());

    forumManager.hardDeleteForumGroupDetail(forumGroupDetailList);
    forumManager = null;

    AuditTrailManager auditTrailManager = new AuditTrailManager(sessionContainer, conn);
    //log down auditTrail when document has hard deleted.
    auditTrailManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, dmsDocument, AuditTrailConstant.ACCESS_TYPE_DELETE, GlobalConstant.AUDIT_TRAIL_DMS_FINAL_VERSION_NUM);
    
    //WorkflowOperationManager wfOperationManager = new WorkflowOperationManager(sessionContainer, conn);
    //wfOperationManager.hardDeleteObjectByClassNameByID(dmsDocument.getClass().getName(), dmsDocument.getID());

    //remove physical file of all version document
    if (!DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())){
      for(int i=0;i <documentVersionList.size();i++){
        DmsVersion tmpVersion = (DmsVersion) documentVersionList.get(i);
        DmsContent tmpContent = docRetrievalManager. getContentByContentID(tmpVersion.getContentID());
        dmsContentManager.deleteDmsDocumentStoreContent(dmsDocument,tmpContent);
        dmsContentDAO.hardDeleteByID(tmpContent.getID());
      }
    }

    dmsDocumentDetailDAO = null;
    dmsDocumentIndexDAO = null ;
    dmsVersionDAO = null;
    dmsContentDAO = null;
    dmsMtmDocumentVersionDAO = null;
    dmsCheckoutHistoryDAO = null;
    dmsDocumentDAO = null;
    docValidateManager.release();
    rootRetrievalManager.release();
    docValidateManager.release();
    auditTrailManager.release();
  }

  /**
   * Copies the document to a destination folder
   *
   * <Pre>
   *
   * Options: copyFileOpt - 1.DmsOperationConstant.COPY_OPERATION_AS_NEW, create a new effective start of the copied
   * document 2.DmsOperationConstant.COPY_OPERATION_AS_OLD, user the effective start and end date of the source document
   *
   * copyVersionOpt -  1.DmsOperationConstant.COPY_ALL_VERSIONS, copy all ther version(s) of the source document.
   *                   2.DmsOperationConstant.COPY_TOP_VERSION, copy the top version of the source document only.
   *
   * During the copy, the update alert is updated audit trail of copy operation Update the index stored in db and lucene
   *
   * </Pre>
   *
   * @param sourceDocument the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID            the destination root ID
   * @param copyFileOpt       copy file document life cycle option
   * @param copyVersionOpt    copy versions of document option
   * @return the copied dmsDocument object
   * @throws UnsupportedOperationException
   * @throws ApplicationException
   * @see com.dcivision.dms.DmsOperationConstant
   * @deprecated This method has deprecated.
   */
  
  public DmsDocument copyDocument(DmsDocument sourceDocument, DmsDocument destinationFolder, Integer rootID, String copyFileOpt,
      String copyVersionOpt) throws UnsupportedOperationException, ApplicationException {
    return this.copyDocument(sourceDocument, destinationFolder, rootID, copyFileOpt, copyVersionOpt, true);
  }

  /**
   * Copies the document to a destination folder
   *
   * <Pre>
   *
   * Options: copyFileOpt - 1.DmsOperationConstant.COPY_OPERATION_AS_NEW, create a new effective start of the copied
   * document 2.DmsOperationConstant.COPY_OPERATION_AS_OLD, user the effective start and end date of the source document
   *
   *  copyVersionOpt - 1.DmsOperationConstant.COPY_ALL_VERSIONS, copy all ther version(s) of the source document.
   *                   2.DmsOperationConstant.COPY_TOP_VERSION, copy the top version of the source document only.
   *
   * bDocumentActive - 1.true, set the record status of the source document as active 2.false, set the record status of
   * the source doucment as pending
   *
   * During the copy, the update alert is updated audit trail of copy operation Update the index stored in db and lucene
   *
   *
   * </Pre>
   *
   * @param sourceDocument the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID            the destination root ID
   * @param copyFileOpt       copy file document life cycle option
   * @param copyVersionOpt    copy versions of document option
   * @param bDocumentActive   after copy set the record status of the source document as active or pending
   * @return the copied dmsDocument object
   * @throws UnsupportedOperationException
   * @throws ApplicationException
   * @see com.dcivision.dms.DmsOperationConstant
   * @deprecated This method has deprecated.
   */
  
  public DmsDocument copyDocument(DmsDocument sourceDocument, DmsDocument destinationFolder, Integer rootID, String copyFileOpt,
      String copyVersionOpt, boolean bDocumentActive) throws UnsupportedOperationException, ApplicationException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsRootDAObject dmsRootDAObject = new DmsRootDAObject(sessionContainer,conn);

    DmsRoot dmsRoot = (DmsRoot)dmsRootDAObject.getObjectByID(sourceDocument.getRootID());
    PermissionManager permManager = sessionContainer.getPermissionManager();
    if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(sourceDocument.getRecordStatus())
        || GlobalConstant.RECORD_PENDING.equals(sourceDocument.getRecordStatus())) {
      if ((!DmsRoot.PERSONAL_ROOT.equals(dmsRoot.getRootType()) && !permManager.hasAccessRight(conn, "D", sourceDocument.getID(),
          WebdavOperationManager.DMS_PERMISSION_COPY_CODE))
          || GlobalConstant.STATUS_LOCKED.equals(sourceDocument.getItemStatus())) {
        throw new ApplicationException(DmsErrorConstant.DMS_MESSAGE_CANNOT_COPY_SUM_DOCUMENT);
      }
    }

    DmsDocument originalDocument = (DmsDocument)sourceDocument.clone();
    DmsDocument newDocument = new DmsDocument();
    String documentType = sourceDocument.getDocumentType();
    if((!DmsDocument.COMPOUND_DOC_TYPE.equals(sourceDocument.getDocumentType())
        && !DmsDocument.EMAIL_DOC_TYPE.equals(sourceDocument.getDocumentType())
        && !DmsDocument.FLOW_DOC_TYPE.equals(sourceDocument.getDocumentType()) && !DmsDocument.FORM_DOC_TYPE.equals(sourceDocument
        .getDocumentType()))) {
      sourceDocument.setRootID(destinationFolder.getRootID());
      sourceDocument.setParentID(destinationFolder.getID());

      DmsRoot documentRoot = (DmsRoot)dmsRootDAObject.getObjectByID(destinationFolder.getRootID());

      //Check for available space
      docValidateManager.checkStorageLimitAvailable(sourceDocument);
      log.debug("Available space exists for current document");

      // create document

      if (DmsOperationConstant.COPY_OPERATION_AS_NEW.equals(copyFileOpt)) {
        sourceDocument.setEffectiveStartDate(new Timestamp(System.currentTimeMillis()));
        if (DmsOperationConstant.DMS_PERSONAL_ROOT.equals(documentRoot.getRootName())) {
          sourceDocument.setEffectiveEndDate(null);
        }
      }
      sourceDocument.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
      sourceDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);
      sourceDocument.setOwnerID(sessionContainer.getUserRecordID());

      if (bDocumentActive) {
        //sourceDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
      } else {
        if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(sourceDocument.getRecordStatus())) {
          sourceDocument.setRecordStatus(GlobalConstant.RECORD_PENDING);
        }
      }
      newDocument = (DmsDocument) dmsDocumentDAO.insertObject(sourceDocument);
    }else{
      newDocument=dmsDocumentDAO.getDocumentByNameParentID(sourceDocument.getDocumentName(),destinationFolder.getID());//taohuaqing
    }
    // get all the version of document (this implementation only valid for linear version)
    DmsVersionDAObject versionDAO = new DmsVersionDAObject(sessionContainer, conn);
    List versionList = new ArrayList();

    if (DmsOperationConstant.COPY_ALL_VERSIONS.equals(copyVersionOpt)){

      versionList = versionDAO.getParentVersionsListByParentIDByDocumentID(null, sourceDocument.getID());
    }else{
      DmsVersion topVersion = (DmsVersion) versionDAO.getTopVersionByDocumentID(sourceDocument.getID());
      topVersion.setVersionNumber("1");
      topVersion.setParentID(new Integer(0));
      topVersion.setVersionLabel(DmsOperationConstant.DMS_ROOT);
      versionList.add(topVersion);
    }
    log.debug("related version list = " + versionList.size());
    log.debug("destination Folder name = " +destinationFolder.getDocumentName());

    DmsContentDAObject contentDAO = new DmsContentDAObject(sessionContainer, conn);
    DmsContent newContent = new DmsContent();
    DmsVersion newVersion = new DmsVersion();
    Boolean supportPhysicalCopy = new Boolean(SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.DMS_SUPPORT_PHYSICAL_FILE_COPY));

    //NOTE: link to physical content can be a abstract link which allow copy operation do not
    // involve copy a content to a separate entity by linking to the content concurrently.
    //if (supportPhysicalCopy.booleanValue()) {//barbin 2006-5-56
      //TODO: Get the original content and create a new physical file
    //}else{
      for (int i = versionList.size()-1; i >= 0; i--) {
        DmsVersion version = (DmsVersion) versionList.get(i);
        // get all content link of version
        DmsContent content = (DmsContent) contentDAO.getObjectByID(version.getContentID());
        content.setID(IDFactory.getInstance().getNextSequence("DMS_CONTENT"));

        newContent = (DmsContent) contentDAO.insertObject(content);
        version.setDocumentID(newDocument.getID());
        version.setContentID(newContent.getID());
        newVersion = (DmsVersion) versionDAO.insertObject(version);
        MtmDocumentVersion newDocVersion = createDocumentVersionRelationship(newDocument, newVersion);
      //}
    }


    //copy document details if any
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    List docDetailList = sourceDocument.getDocumentDetails();
    List newDocDetailList = new ArrayList();
    if (docDetailList != null){
      for(int i=0 ; i<docDetailList.size(); i++){
        DmsDocumentDetail docDetail = (DmsDocumentDetail) docDetailList.get(i);
        docDetail.setDocumentID(newDocument.getID());
        docDetail = (DmsDocumentDetail)docDetailDAO.insertObject(docDetail);
        newDocDetailList.add(docDetail);
        if (i==0) {
          newDocument.setUserDefinedFieldID(docDetail.getUserDefinedFieldID());
        }
      }
    }

    log.debug("created doc detail ");
    List udfDetailList = docRetrievalManager.getUDFDetailList(newDocument.getUserDefinedFieldID());
    newDocument.setUdfDetailList(udfDetailList);
    newDocument.setDocumentDetails(newDocDetailList);
    //end of copy document details

    //set the new value to old document
    sourceDocument.setParentID(newDocument.getParentID());
    sourceDocument.setRootID(newDocument.getRootID());
    sourceDocument.setUdfDetailList(newDocument.getUdfDetailList());
    sourceDocument.setDocumentDetails(newDocument.getDocumentDetails());
    sourceDocument.setID(newDocument.getID());

    /* Check for Document Relationship type */
    MtmDocumentRelationshipDAObject mtmRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    MtmDocumentRelationship mtmRelationship = (MtmDocumentRelationship) mtmRelationshipDAO.getObjectByRelatedDocID(sourceDocument.getID(),
        null);

    if (mtmRelationship!=null){
      mtmRelationship.setRelatedDocumentID(newDocument.getID());
      MtmDocumentRelationship newRelatedDoc = (MtmDocumentRelationship)mtmRelationshipDAO.insertObject(mtmRelationship);
    }



    //if difference dms root location master copy the physical document
    RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);
    if(originalDocument.getRootID().intValue()!=destinationFolder.getRootID().intValue()){
      DmsLocMaster sourceRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(originalDocument);
      DmsLocMaster destinationRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(destinationFolder);

      if(sourceRootLoc.getID().intValue()!= destinationRootLoc.getID().intValue()){
        if(!sourceRootLoc.getLocPath().equals(destinationRootLoc.getLocPath())){
           //move the physical document
          moveCopyPhysicalDocument(originalDocument, sourceRootLoc, destinationRootLoc, DmsOperationConstant.COPY_OPERATION, copyVersionOpt);
        }
      }
    }


    // Full text Insert
    //InputStream data = new IndexManager(this.sessionContainer, this.conn).getContent(sourceDocument.getID());
    //newDocument.setScanDocumentForFullText(true);
    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_COPY,
        DmsDocumentIndexCache.ACTION_TYPE_UPDATE_ALL, originalDocument.getID());
    this.indexLUCENE(indexCache, newDocument, null, null);


    // Alert copy document
    try {
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      am.call(UpdateAlert.DOCUMENT_TYPE, destinationFolder.getID(), UpdateAlert.CREATE_ACTION, sourceDocument.getDocumentName(), null,
          null, null, newDocument.getID());
      am.release();
    } catch (Exception e) {
      log.error("Error when doing alert", e);

    }

    // Log down in audit trail
    if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDocument.getDocumentType()))) {// barbin
                                                                                                                                  // EIP-1296
      AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, sourceDocument, AuditTrailConstant.ACCESS_TYPE_COPY, null);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDocument, AuditTrailConstant.ACCESS_TYPE_COPY_CREATE, null);
      auditManager.release();
    }

    dmsDocumentDAO=null;
    versionDAO = null;
    contentDAO=null;
    docDetailDAO=null;
    mtmRelationshipDAO=null;
    dmsRootDAObject=null;
    docRetrievalManager.release();
    docValidateManager.release();

    return newDocument;
  }

  /**
   * Moves the source document to a destination folder
   *
   * <pre>
   *
   * During the move,
   * the update alert is updated
   * audit trail of move operation
   * Update the index stored in db and lucene
   *
   * </pre>
   *
   * @param sourceDocument  the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID  the destination folder rootID
   * @throws UnsupportedOperationException
   * @throws ApplicationException
   * @deprecated This method has deprecated.
   */
  
  public void moveDocument(DmsDocument sourceDocument, DmsDocument destinationFolder, Integer rootID) throws UnsupportedOperationException,
      ApplicationException {
    moveDocument(sourceDocument, destinationFolder, rootID, false, true);
  }

  /**
   * Moves the source document to a destination folder
   *
   * <pre>
   *
   * During the move,
   * the update alert is updated
   * audit trail of move operation
   * Update the index stored in db and lucene
   *
   * </pre>
   *
   * @param sourceDocument  the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID  the destination folder rootID
   * @param byMoveFolder true if it is trigger by move Folder operation, then no need to check duplicate name unser same
   *          folder level.
   * @throws UnsupportedOperationException
   * @throws ApplicationException
   * @deprecated This method has deprecated.
   */
  
  public void moveDocument(DmsDocument sourceDocument, DmsDocument destinationFolder, Integer rootID, boolean byMoveFolder)
      throws UnsupportedOperationException, ApplicationException {
    moveDocument(sourceDocument, destinationFolder, rootID, byMoveFolder, true);
  }

  /**
   * Moves the source document to a destination folder
   *
   * <pre>
   *
   * During the move,
   * the update alert is updated
   * audit trail of move operation
   * Update the index stored in db and lucene
   *
   * </pre>
   *
   * @param sourceDocument  the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID  the destination folder rootID
   * @param byMoveFolder true if it is trigger by move Folder operation, then no need to check duplicate name unser same
   *          folder level.
   * @param bDocumentActive true if moved document record status set to active, false then set to pending
   * @throws UnsupportedOperationException
   * @throws ApplicationException
   * @deprecated This method has deprecated.
   */
  
  public void moveDocument(DmsDocument sourceDocument, DmsDocument destinationFolder, Integer rootID, boolean byMoveFolder,
      boolean bDocumentActive) throws UnsupportedOperationException, ApplicationException {
    PermissionManager permManager = sessionContainer.getPermissionManager();
    DmsRootDAObject dmsRootDAObject = new DmsRootDAObject(sessionContainer,conn);

    DmsRoot dmsRoot = (DmsRoot)dmsRootDAObject.getObjectByID(sourceDocument.getRootID());
    if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(sourceDocument.getRecordStatus())
        || GlobalConstant.RECORD_PENDING.equals(sourceDocument.getRecordStatus())) {
      if ((!DmsRoot.PERSONAL_ROOT.equals(dmsRoot.getRootType()) && !permManager.hasAccessRight(conn, "D", sourceDocument.getID(),
          WebdavOperationManager.DMS_PERMISSION_MOVE_CODE))
          || GlobalConstant.STATUS_LOCKED.equals(sourceDocument.getItemStatus())) {
        throw new ApplicationException(DmsErrorConstant.DMS_MESSAGE_CANNOT_MOVE_SUM_DOCUMENT);
      }
    }
    // create document
    Integer originalParentID = sourceDocument.getParentID();
    DmsDocument originalDocument =(DmsDocument) sourceDocument.clone();

    sourceDocument.setRootID(destinationFolder.getRootID());
    sourceDocument.setParentID(destinationFolder.getID());
    if (bDocumentActive) {
      //sourceDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
    } else {
      if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(sourceDocument.getRecordStatus())) {
        sourceDocument.setRecordStatus(GlobalConstant.RECORD_PENDING);
      }
    }
    log.debug("moving with folder? "+byMoveFolder);

    //check duplicate name of same level if config file defined
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
    if (!byMoveFolder) {
      docValidateManager.checkDuplicateNameSupport(sourceDocument);
      log.debug("No duplicate name exists");
    }

    //Check for available space
    docValidateManager.checkStorageLimitAvailable(sourceDocument);
    log.debug("Available space exists for current document");

    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsDocument newDocument = (DmsDocument) dmsDocumentDAO.updateObject(sourceDocument);
    log.debug("moved Document root ID " + newDocument.getRootID() + " parent ID " + newDocument.getParentID());

    //update all sessionctn permission string in cache
    PermissionManager.firePermissionChanged(GlobalConstant.OBJECT_TYPE_DOCUMENT,newDocument.getID());

    // Update full text index after move document.
    // this.indexDocument(newDocument, null, GlobalConstant.OP_MODE_UPDATE, new String[]{"DOCUMENT_NAME", "ROOT_ID",
    // "PARENT_ID"});
    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_MOVE,
        DmsDocumentIndexCache.ACTION_TYPE_UPDATE_STANDARD, originalDocument.getID());
    this.indexLUCENE(indexCache, newDocument, null, null);

    // handle move of physical document
    RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);

    if(originalDocument.getRootID().intValue()!=destinationFolder.getRootID().intValue()){
      DmsLocMaster sourceRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(originalDocument);
      DmsLocMaster destinationRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(destinationFolder);

      if(sourceRootLoc.getID().intValue()!= destinationRootLoc.getID().intValue()){
        if(!sourceRootLoc.getLocPath().equals(destinationRootLoc.getLocPath())){
           //move the physical document
          moveCopyPhysicalDocument(originalDocument, sourceRootLoc, destinationRootLoc, DmsOperationConstant.MOVE_OPERATION , null);
        }
      }
    }


    //moveDocument
    try {
      AlertManager alertManager = new AlertManager(sessionContainer, conn);
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      UpdateAlert updateAlert=alertManager.getUpdateAlertByObjectTypeObjectID(UpdateAlert.DOCUMENT_TYPE,sourceDocument.getID());
      UpdateAlert originalParentUpdateAlert = alertManager.getUpdateAlertByObjectTypeObjectID(UpdateAlert.DOCUMENT_TYPE, originalParentID);
      if(!byMoveFolder){
        if(!Utility.isEmpty(updateAlert)){
          this.dealUpdateAlert(updateAlert,UpdateAlert.DELETE_ACTION);
          am.call(UpdateAlert.DOCUMENT_TYPE, sourceDocument.getID(), UpdateAlert.MOVE_ACTION, sourceDocument.getDocumentName(), null, null,
              null, sourceDocument.getID());
        }
        if(!Utility.isEmpty(originalParentUpdateAlert)){
          if(!this.checkSameUserSetAlert(originalParentUpdateAlert,UpdateAlert.DELETE_ACTION,updateAlert,UpdateAlert.DELETE_ACTION)){
            this.dealUpdateAlert(originalParentUpdateAlert,UpdateAlert.DELETE_ACTION);
            am.call(UpdateAlert.DOCUMENT_TYPE, originalParentID, UpdateAlert.MOVE_ACTION, sourceDocument.getDocumentName(), null, null,
                null, sourceDocument.getID());
          }
        }
        UpdateAlert newParentUpdateAlert = alertManager.getUpdateAlertByObjectTypeObjectID(UpdateAlert.DOCUMENT_TYPE, sourceDocument
            .getParentID());
        if(!Utility.isEmpty(newParentUpdateAlert)){
          if (!this.checkSameUserSetAlert(newParentUpdateAlert, UpdateAlert.CREATE_ACTION, updateAlert, UpdateAlert.DELETE_ACTION)
              && !this.checkSameUserSetAlert(newParentUpdateAlert, UpdateAlert.CREATE_ACTION, originalParentUpdateAlert,
                  UpdateAlert.DELETE_ACTION)) {
            this.dealUpdateAlert(newParentUpdateAlert,UpdateAlert.CREATE_ACTION);
            am.call(UpdateAlert.DOCUMENT_TYPE, sourceDocument.getParentID(), UpdateAlert.MOVE_ACTION, sourceDocument.getDocumentName(),
                null, null, null, sourceDocument.getID());
          }
        }
      }else{
        if(!Utility.isEmpty(updateAlert)){
          if(!this.checkSameUserSetAlert(originalParentUpdateAlert,UpdateAlert.DELETE_ACTION,updateAlert,UpdateAlert.DELETE_ACTION)){
            this.dealUpdateAlert(updateAlert,UpdateAlert.DELETE_ACTION);
            am.call(UpdateAlert.DOCUMENT_TYPE, sourceDocument.getID(), UpdateAlert.MOVE_ACTION, sourceDocument.getDocumentName(), null,
                null, null, sourceDocument.getID());
          }
        }
      }
      am.release();

      // log down in audit trail
      if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDocument.getDocumentType()))) {// barbin
                                                                                                                                    // EIP-1296
        AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
        auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDocument, AuditTrailConstant.ACCESS_TYPE_MOVE, null);
        auditManager.release();

        // Clear the permission cache of that document.
        sessionContainer.getPermissionManager().clearPermissionCache(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDocument.getID());
      }
    } catch (Exception e) {
      log.error("Error when doing audit trail", e);
    }

    dmsDocumentDAO = null;
    docValidateManager.release();
    rootRetrievalManager.release();
  }

  /**
   * Rename a document
   *
   * <pre>
   *
   *  During the rename,
   *  the update alert is updated
   *  audit trail of rename operation
   *  Update the index stored in db and lucene
   *
   * </pre>
   *
   * @param document the dmsDocument with new document name
   * @return the dmsDocument object after rename
   * @throws UnsupportedOperationException
   * @throws ApplicationException
   */
  public DmsDocument renameRecord(DmsDocument document) throws UnsupportedOperationException, ApplicationException {
    // check duplicate name of same level if config file defined
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
    DmsDocument newDocument = null;

    // validate duplicated name (lee add try catch finally 06/11/29 EIP-539)
    docValidateManager.checkAndLockDuplicateNameCache(document);

    // valicate duplicated name from databse
    // docValidateManager.checkDuplicateNameSupport(document);

    log.debug("No duplicate name exists");

    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    newDocument = (DmsDocument) dmsDocumentDAO.documentSQLExecute("UPDATE", "DOCUMENT_NAME", document.getDocumentName(), document);
    // bill add for EIP-1461 start
    MtmWorkflowProgressSystemObjectDAObject mtmWorkflowProgressSystemObjectDAO = new MtmWorkflowProgressSystemObjectDAObject(
        sessionContainer, conn);
    List listResult = mtmWorkflowProgressSystemObjectDAO.getListByBeanClassNameObjectID("com.dcivision.dms.bean.DmsDocument", document
        .getID());
    if (!Utility.isEmpty(listResult)) {
      for (int index = 0; index < listResult.size(); index++) {
        MtmWorkflowProgressSystemObject tmpMtmWorkflowProgressSystemObject = (MtmWorkflowProgressSystemObject) listResult.get(index);
        Map objectMap = new HashMap();
        objectMap.put("WORKFLOW_OBJECT", newDocument);
        tmpMtmWorkflowProgressSystemObject.setParameterObject(objectMap);
        // update related object name after rename document
        mtmWorkflowProgressSystemObjectDAO.updateObject(tmpMtmWorkflowProgressSystemObject);
      }
    }
    // bill add for EIP-1461 end
    newDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
    // newDocument.setRecordStatus(document.getRecordStatus());
    // newDocument.setUpdaterName(UserInfoFactory.getUserFullName(newDocument.getUpdaterID()));
    // newDocument.setCreatorName(UserInfoFactory.getUserFullName(newDocument.getCreatorID()));
    log.debug("Renamed Document  " + newDocument.getDocumentName());

    // Update full text index after rename document.
    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_UPDATE,
        DmsDocumentIndexCache.ACTION_TYPE_UPDATE_NAME, newDocument.getID());
    this.indexLUCENE(indexCache, newDocument, null, null);

    // cancel by beyond ,rename not need reconvert Document Name for EIP-2306
    // Update all document converted name in DmsContent tables.
    // not physical file document type not need update convert name
    /*
     * if(!DmsDocument.DOCUMENT_LINK.equals(document.getDocumentType())&&
     * !DmsDocument.FOLDER_TYPE.equals(document.getDocumentType())&&
     * !DmsDocument.PAPER_DOC_TYPE.equals(document.getDocumentType()) ){ updateAllDocumentConvertedName(document); }
     */

    // Alert rename document.
    try {
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      am.call(UpdateAlert.DOCUMENT_TYPE, newDocument.getID(), UpdateAlert.UPDATE_ACTION, document.getDocumentName(), null, null, null);
      am.release();
    } catch (Exception e) {
      log.error("Error when doing audit trail", e);
    }

    // Audit rename document.
    if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDocument.getDocumentType()))) {// barbin
                                                                                                                                  // EIP-1296
      AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
      if (DmsDocument.DOCUMENT_LINK.equals(newDocument.getDocumentType())) {
        auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDocument, AuditTrailConstant.ACCESS_TYPE_RENAME_SHORTCUT, null);// add
      } else {
        auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDocument, AuditTrailConstant.ACCESS_TYPE_RENAME, null);
      }
      auditManager.release();
    }
    dmsDocumentDAO = null;

    docValidateManager.release();

    return newDocument;
  }

  /**
  *  Rename a document name, will update all its converted name in DmsContent and physical location
  *
    *  @param      dmsDocument              The object of DmsDocument with detail information
    *  @return     void
    *  @throws     ApplicationException     Throws when create operation fault.
   *
  *  <pre>
  *   ApplicationException with the following message codes will be thrown
  *   DmsErrorConstant.RENAME_FILE_ERROR - Rename physical file name error
  *   DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND - No converted doucment name handle class found error
  *  </pre>
   *
  *  @see com.dcivsion.dms.DmsErrorConstant
    */

  public void updateAllDocumentConvertedName(DmsDocument document) throws ApplicationException {

    try {
      this.documentNameConvertor = (DmsDocumentNameConvertor) Class.forName(
        SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_NAME_CONVERTOR_CLASS)).newInstance();
    } catch (Exception e) {
      log.error("Name Convertor class not found.", e);
      throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
    }
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    List versionList = docRetrievalManager.getVersionListByDocumentID(document.getID());
    DmsContentDAObject dmsContentDAO = new DmsContentDAObject(sessionContainer, conn);
    DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);
    for (int i=0; i<versionList.size(); i++){
      DmsVersion version = (DmsVersion)versionList.get(i);
      log.debug("version number = " + version.getVersionNumber());
      log.debug("content number = " + version.getContentID());
      if (version!=null) {
        document.setVersionNumber(version.getVersionNumber());
        if (version.getContentID()!=null && version.getContentID().intValue()>0){
          DmsContent content = (DmsContent) dmsContentDAO.getObjectByID(version.getContentID());
          //use the shortDocumentNameConvertor
          String  convertClassName=SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_NAME_CONVERTOR_CLASS);
          String newConvertedName = this.documentNameConvertor.encryptDocumentName(document);
          if(convertClassName.indexOf("ShortDocumentNameConvertor")>0){
            DmsDocument tempDmsDocument = new DmsDocument();
            tempDmsDocument.setID(content.getID());
            newConvertedName = this.documentNameConvertor.encryptDocumentName(tempDmsDocument);
          }

          //Update physical filename in storage location
//          String oldConvertedName = content.getConvertedName();
          try{
            if(!DmsDocument.DOCUMENT_LINK.equals(document.getDocumentType())
               && !DmsDocument.PAPER_DOC_TYPE.equals(document.getDocumentType())
               && !DmsDocument.FOLDER_TYPE.equals(document.getDocumentType())
               && !DmsDocument.EMAIL_DOC_TYPE.equals(document.getDocumentType())){
                 dmsContentManager.renameDmsDocumentStoreContent(document,content,newConvertedName);
               }
          }catch(ContentStoreException e){
            if(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_RENAME_FAILED.equals(e.getMsgCode())){
              log.error("Rename file operation fail.");
              throw new ApplicationException(DmsErrorConstant.RENAME_FILE_ERROR);
            }else{
              throw e;
            }
          }

          //Update DMS_CONTENT table; change the converted name
          content.setConvertedName(newConvertedName);
          dmsContentDAO.updateObject(content);

        }
      }
    }
    dmsContentDAO=null;
    docRetrievalManager.release();
  }

  /**
   * Creates and retrieve the new Folder
   *
   * <Pre>
   *
   * Create the new folder, it creates new version of the new folder it create new content of the new folder it updates
   * the index store in db and lucene it records the new folder operation in audit trail
   *
   * </pre>
   *
   *  @param      dmsDocument              The object of DmsDocument with detail information
   *  @return     DmsDocument              The (DmsDocument) of corresponding dmsDocument.
   *  @throws     ApplicationException     Throws when create operation fault.
   *
   *  <pre>
   *
   *   ApplicationException with the following message codes will be thrown
   *   DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND - No converted doucment name handle class found error
   *
   *  </pre>
   */
  public DmsDocument createFolder(DmsDocument dmsDocument) throws ApplicationException{
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
    //set Document Reminder Amount
    String tmpReminder = dmsDocument.getReminderType();
    Integer reminderAmount = null;
    String reminderType = null;
    if (!Utility.isEmpty(tmpReminder)){
      StringTokenizer sk = new StringTokenizer(dmsDocument.getReminderType(), ";", false);
      if (sk.hasMoreTokens()) {
        reminderAmount = TextUtility.parseIntegerObj(sk.nextToken());
      }
      if (sk.hasMoreTokens()) {
        reminderType = sk.nextToken();
      }
      dmsDocument.setReminderAmount(reminderAmount);
      dmsDocument.setReminderType(reminderType);
    }
    DmsDocument newDmsDocument = new DmsDocument();

    //validate duplicated name (lee add try catch finally 06/11/29 EIP-539)
    boolean checkDuplicateName = docValidateManager.checkAndLockDuplicateNameCache(dmsDocument);
    //boolean checkDuplicateName = docValidateManager.checkDuplicateNameSupport(dmsDocument);


    if (!checkDuplicateName) { //checked duplicate name for folder, still can pass
      newDmsDocument = docRetrievalManager.getDocument(dmsDocument.getID());
      newDmsDocument.setReminderAmount(reminderAmount);
      newDmsDocument.setReminderType(reminderType);
    } else {
      //Create Folder Document
      DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
      newDmsDocument = (DmsDocument)dmsDocumentDAO.insertObject(dmsDocument);


      //copy document details if any
      List newDetailList = new ArrayList();
      DmsDocumentDetail docDetail = null;
      DmsDocumentDetail newDocDetail = null;

      List detailList = dmsDocument.getDocumentDetails();
      if (!Utility.isEmpty(detailList)) {
        for (int i = 0; i < detailList.size(); i++) {
          docDetail = (DmsDocumentDetail)detailList.get(i);
          docDetail.setDocumentID(newDmsDocument.getID());
          newDocDetail = this.createDocumentDetail(docDetail);
          newDetailList.add(newDocDetail);
        }
        List udfDetailList = docRetrievalManager.getUDFDetailList(newDocDetail.getUserDefinedFieldID());
        newDmsDocument.setUserDefinedFieldID(newDocDetail.getUserDefinedFieldID());
        newDmsDocument.setUdfDetailList(udfDetailList);
        newDmsDocument.setDocumentDetails(newDetailList);
      } //end of creating doc detail for provided document detail set
/*
       * DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn); List
       * docDetailList = dmsDocument.getDocumentDetails(); List newDocDetailList = new ArrayList(); if (docDetailList !=
       * null){ for(int i=0 ; i<docDetailList.size(); i++){ DmsDocumentDetail docDetail = (DmsDocumentDetail)
       * docDetailList.get(i); docDetail.setDocumentID(newDmsDocument.getID()); docDetail =
       * (DmsDocumentDetail)docDetailDAO.insertObject(docDetail); newDocDetailList.add(docDetail); if (i==0) {
       * newDmsDocument.setUserDefinedFieldID(docDetail.getUserDefinedFieldID()); } } List udfDetailList =
       * docRetrievalManager.getUDFDetailList(newDocDetailList.getUserDefinedFieldID());
       * newDmsDocument.setUserDefinedFieldID(newDocDetailList.getUserDefinedFieldID());
       * newDmsDocument.setUdfDetailList(udfDetailList); newDmsDocument.setDocumentDetails(newDocDetailList); }
*/

      /*
       * Comment by Zoe - no need to Create Physical Folder String foldersDir =
       * docRetrievalManager.getFoldersDirectories(newDmsDocument).toString();
       */
      //Create physical root directory & Content
      try {
        this.documentNameConvertor = (DmsDocumentNameConvertor) Class.forName(
            SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_NAME_CONVERTOR_CLASS)).newInstance();
      } catch (Exception e) {
        log.error("Name Convertor class not found.", e);
        throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
      }
      String convertedName = this.documentNameConvertor.encryptDocumentName(newDmsDocument);
      /*
       * Comment By Zoe - No level Needed String personalFolderPath = foldersDir+convertedName; log.debug("detail
       * FolderPath = " + personalFolderPath); File personalFolder = new File(personalFolderPath); if
       * (!personalFolder.exists()) personalFolder.mkdir();
       */
      //Create Folder Content
      DmsContent newContent = new DmsContent();
      newContent.setConvertedName(convertedName);
      DmsContentDAObject dmsContentDAO = new DmsContentDAObject(sessionContainer, conn);
      newContent = (DmsContent)dmsContentDAO.insertObject(newContent);
      newDmsDocument.setContentID(newContent.getID());


      DmsVersion newDmsVersion = createDocumentVersion(newDmsDocument, newContent);
      newDmsDocument.setVersionID(newDmsVersion.getID());
      newDmsDocument.setVersionParentID(newDmsVersion.getParentID());
      newDmsDocument.setVersionLabel(newDmsVersion.getVersionLabel());
      newDmsDocument.setVersionNumber(newDmsVersion.getVersionNumber());
      DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDmsDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_INSERT,
          DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_PARAM, null);
      this.indexLUCENE(indexCache, newDmsDocument, newContent, null);

      /* CreateDocument; check for alert notification */
      if (dmsDocument.getParentID().intValue() != 0) {
        DmsDocument parentDoc = (DmsDocument) dmsDocumentDAO.getObjectByID(dmsDocument.getParentID());
        try {
          AdapterMaster am = new AdapterMaster(sessionContainer, conn);
          am.call(UpdateAlert.DOCUMENT_TYPE, parentDoc.getID(), UpdateAlert.CREATE_ACTION, newDmsDocument.getDocumentName(), null, null,
              null, newDmsDocument.getID());
          am.release();
        } catch (Exception e) {
          log.error("Error when doing alert", e);
        }
      }

      //audit create folder
      if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDmsDocument.getDocumentType()))) {// barbin
                                                                                                                                      // EIP-1296
        AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
        auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDmsDocument, AuditTrailConstant.ACCESS_TYPE_CREATE_FOLDER,
                                newDmsVersion.getVersionNumber());
        auditManager.release();
      }
      dmsDocumentDAO=null;
    }

      // lee.lv add for EIP-1081 in 06/12/01
      /* CreateDocument Reminder; setup reminder notification */
      if (!Utility.isEmpty(newDmsDocument.getReminderType())){
        UpdateAlert updateAlert = new UpdateAlert();
        updateAlert.setObjectType(UpdateAlert.DOCUMENT_TYPE);
        updateAlert.setObjectID(newDmsDocument.getID());
        AlertManager alertManager = new AlertManager(sessionContainer, conn);
        alertManager.newReminderAlert(updateAlert, UpdateAlert.DOCUMENT_TYPE, newDmsDocument.getID(), newDmsDocument);
        alertManager.release();
      }
      // lee.lv add for EIP-1081 in 06/12/01


    docRetrievalManager.release();
    docValidateManager.release();
    return newDmsDocument; //newList;
  }

  /**
   * Creates a new folder for the scan operation process.
   * <P>
   * This methods mainly for create folder structure base on the paraScan clientAutotracker, the invalid chars in folder
   * name on the OS will replace with "-" when create a new folder in DMS.
   * </P>
   *
   * @param dmsDocument
   * @return
   * @throws     ApplicationException     Throws when create operation fault.
   *
   *  <pre>
   *   ApplicationException with the following message codes will be thrown
   *   DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND - No converted doucment name handle class found error
   *  </pre>
   */

  public DmsDocument createFolderFromScan(DmsDocument dmsDocument) throws ApplicationException{
      // check duplicate name of same level if config file defined
      DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
      DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);

      DmsDocument newDmsDocument = null;

      //validate duplicated name (lee add try catch finally 06/11/29 EIP-539)
      boolean checkDuplicateName = docValidateManager.checkAndLockDuplicateNameCache(dmsDocument);
      //boolean checkDuplicateName = docValidateManager.checkDuplicateNameSupport(dmsDocument);
      newDmsDocument = new DmsDocument();
      //check the permission
    docValidateManager.checkHasPermissionOnObject(GlobalConstant.OBJECT_TYPE_DOCUMENT, dmsDocument.getParentID(), dmsDocument.getRootID(),
        "I");
      log.debug(".................................Has permission on target folder");

      if (!checkDuplicateName) { //checked duplicate name for folder, still can pass
        //newDmsDocument = (DmsDocument) docRetrievalManager.getDocument(dmsDocument.getID());
          newDmsDocument = docRetrievalManager.getDuplicateNameDocSameLevel(dmsDocument);
    } else {
        //Create Folder Document
        DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);

        //get rid of invalid char
        dmsDocument.setDocumentName(TextUtility.replaceInvalidChar(dmsDocument.getDocumentName(),"-"));

        newDmsDocument = (DmsDocument)dmsDocumentDAO.insertObject(dmsDocument);

      /*
       * Comment by Zoe - no need to Create Physical Folder String foldersDir =
       * docRetrievalManager.getFoldersDirectories(newDmsDocument).toString();
         */
        //Create physical root directory & Content
        try {
        this.documentNameConvertor = (DmsDocumentNameConvertor) Class.forName(
            SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_NAME_CONVERTOR_CLASS)).newInstance();
        } catch (Exception e) {
          log.error("Name Convertor class not found.", e);
          throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
        }
        String convertedName = this.documentNameConvertor.encryptDocumentName(newDmsDocument);
      /*
       * Comment By Zoe - No level Needed String personalFolderPath = foldersDir+convertedName; log.debug("detail
       * FolderPath = " + personalFolderPath); File personalFolder = new File(personalFolderPath); if
       * (!personalFolder.exists()) personalFolder.mkdir();
         */
        //Create Folder Content
        DmsContent newContent = new DmsContent();
        newContent.setConvertedName(convertedName);
        DmsContentDAObject dmsContentDAO = new DmsContentDAObject(sessionContainer, conn);
        newContent = (DmsContent)dmsContentDAO.insertObject(newContent);
        newDmsDocument.setContentID(newContent.getID());


        DmsVersion newDmsVersion = createDocumentVersion(newDmsDocument, newContent);
        newDmsDocument.setVersionID(newDmsVersion.getID());
        newDmsDocument.setVersionParentID(newDmsVersion.getParentID());
        newDmsDocument.setVersionLabel(newDmsVersion.getVersionLabel());
        newDmsDocument.setVersionNumber(newDmsVersion.getVersionNumber());
      DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDmsDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_INSERT,
          DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_PARAM, null);
        this.indexLUCENE(indexCache, newDmsDocument, newContent, null);

        //audit create folder
      if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDmsDocument.getDocumentType()))) {// barbin
                                                                                                                                      // EIP-1296
          AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
          auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDmsDocument, AuditTrailConstant.ACCESS_TYPE_CREATE_FOLDER,
                                  newDmsVersion.getVersionNumber());
          auditManager.release();
        }
        dmsDocumentDAO=null;
      }

      docRetrievalManager.release();
      docValidateManager.release();
      return newDmsDocument; //newList;
    }

  /**
   * Deletes folder and also delete its sub document under this folder.
   * <P>
   * If there are checkout document(s) under this folder then other non checkout document(s) under this folders will be
   * deleted. However, the folder will not be delete.
   *
   * If the folder is deleted, its update alert will also removed.
   * </P>
   *
   * @param folder the dmsDocument object of the folder
   * @throws ApplicationException
   * @throws SubElementContainedException
   */
  public void deleteFolder(DmsDocument folder) throws ApplicationException, SubElementContainedException {
    Integer folderID = folder.getID();
    String folderName = folder.getDocumentName();
    // check whether there is document within the folder
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    List documentList = dmsDocumentDAO.getListByParentID(folder.getID(), folder.getRootID(),"*", true);
    DmsDocument childDocument = new DmsDocument();
    boolean hasNotAllowDocument = false;
    //delete children
    for (int i=0; i < documentList.size(); i++){
      childDocument = (DmsDocument) documentList.get(i);
      if (DmsDocument.FOLDER_TYPE.equals(childDocument.getDocumentType())
          || DmsDocument.COMPOUND_DOC_TYPE.equals(childDocument.getDocumentType())
          || DmsDocument.PAPER_DOC_TYPE.equals(childDocument.getDocumentType())) {
        deleteFolder(childDocument);
      } else {
        // checkouted document not allow delete
        if(!DmsVersion.EXCLUSIVE_LOCK.equals(childDocument.getItemStatus())){
            deleteDocument(childDocument);
        }else{
            hasNotAllowDocument = true;
        }

      }
    }

    //finally, delete the folder
    //have checkout document ,not allow delete
    if(hasNotAllowDocument == false){
        deleteDocument(folder);
    }


    //delete folder; check for alert notification
    try {
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      am.call(UpdateAlert.DOCUMENT_TYPE, folderID, UpdateAlert.DELETE_ACTION, folderName, null, null, null, folder.getID() );
      am.release();
    } catch (Exception e) {
      log.error("Error when doing alert", e);
    }

    dmsDocumentDAO=null;

  }

  /**
  * Copies a folder to destination folder, all the document(s) under the source will also be copied.
   *
  * <Pre>
  *
   * Options: copyFileOpt - 1.DmsOperationConstant.COPY_OPERATION_AS_NEW, create a new effective start of the copied
   * folder and its subdocument 2.DmsOperationConstant.COPY_OPERATION_AS_OLD, use the effective start and end date of
   * the source folder and its subdocument
  *
   * copyVersionOpt - 1.DmsOperationConstant.COPY_ALL_VERSIONS, copy all ther version(s) of the source folder
   * subdocument(s). 2.DmsOperationConstant.COPY_TOP_VERSION, copy the top version of the source folde subdocument(s)
   * only.
  *
   * structureOpt - 1.DmsOperationConstant.COPY_STRUCTURE_ONLY, copy only the folder structure, only sub folders is
   * copied 2.DmsOperationConstant.NO_STRUCTURE_COPY, copy all the sub document(s) and sub folder(s)
  *
   * During the copy, the update alert is updated audit trail of copy operation
  *
   *
  * </Pre>
  *
  * @param sourceFolder the source dmsDocument object
  * @param destinationFolder the destination folder dmsDocument object
  * @param rootID            the destination root ID
  * @param copyFileOpt       copy file document life cycle option
  * @param copyVersionOpt    copy versions of document option
  * @param structureOpt      copy the folder structure only or include all the sub folder(s) and document(s)
  * @return the copied dmsDocument object
   * @throws ApplicationException
  * @see com.dcivision.dms.DmsOperationConstant
   * @deprecated This method has deprecated.
   */
  public DmsDocument copyFolder(DmsDocument sourceFolder, DmsDocument destinationFolder, Integer rootID, String copyFileOpt,
      String copyVersionOpt, String structureOpt) throws ApplicationException {
    return this.copyFolder(sourceFolder, destinationFolder, rootID, copyFileOpt, copyVersionOpt, structureOpt, true);
  }

  /**
   * Copies a folder to destination folder, all the document(s) under the source will also be copied.
   *
   * <Pre>
   *
   * Options: copyFileOpt - 1.DmsOperationConstant.COPY_OPERATION_AS_NEW, create a new effective start of the copied
   * folder and its subdocument 2.DmsOperationConstant.COPY_OPERATION_AS_OLD, use the effective start and end date of
   * the source folder and its subdocument
   *
   * copyVersionOpt - 1.DmsOperationConstant.COPY_ALL_VERSIONS, copy all ther version(s) of the source folder
   * subdocument(s). 2.DmsOperationConstant.COPY_TOP_VERSION, copy the top version of the source folde subdocument(s)
   * only.
   *
   * structureOpt - 1.DmsOperationConstant.COPY_STRUCTURE_ONLY, copy only the folder structure, only sub folders is
   * copied 2.DmsOperationConstant.NO_STRUCTURE_COPY, copy all the sub document(s) and sub folder(s)
   *
   * bDocumentActive - 1.true, set the record status of the source folder and its sub document(s) as active 2.false, set
   * the record status of the source folder and its sub doucment(s) as pending
   *
   * During the copy, the update alert is updated audit trail of copy operation
   *
   *
   * </Pre>
   *
   * @param sourceFolder the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID            the destination root ID
   * @param copyFileOpt       copy file document life cycle option
   * @param copyVersionOpt    copy versions of document option
   * @param structureOpt      copy the folder structure only or include all the sub folder(s) and document(s)
   * @param bDocumentActive   after copy set the record status of the source document as active or pending
   * @return the copied dmsDocument object
   * @throws ApplicationException
   * @see com.dcivision.dms.DmsOperationConstant
   * @deprecated This method has deprecated.
   */
  public DmsDocument copyFolder(DmsDocument sourceFolder, DmsDocument destinationFolder, Integer rootID, String copyFileOpt,
      String copyVersionOpt, String structureOpt, boolean bDocumentActive) throws ApplicationException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DmsRootDAObject dmsRootDAObject = new DmsRootDAObject(sessionContainer,conn);

    DmsRoot dmsRoot = (DmsRoot)dmsRootDAObject.getObjectByID(sourceFolder.getRootID());
    DmsRoot documentRoot = (DmsRoot)dmsRootDAObject.getObjectByID(destinationFolder.getRootID());
    DmsDocument sourceFolderTemp = docRetrievalManager.getDocument(sourceFolder.getID());

    sourceFolder.setParentID(destinationFolder.getID());
    sourceFolder.setRootID(rootID);
    DmsDocument copiedDocument = null;

    //if destination is personal then set is null
    if (DmsOperationConstant.DMS_PERSONAL_ROOT.equals(documentRoot.getRootName())) {
      sourceFolder.setEffectiveEndDate(null);
    }

    //Create New Copied Folder
    DmsDocument newDestinationFolder = new DmsDocument();
    if (DmsOperationConstant.COPY_OPERATION_AS_NEW.equals(copyFileOpt)){
      sourceFolder.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
      sourceFolder.setEffectiveStartDate(new Timestamp(System.currentTimeMillis()));
      sourceFolder.setItemStatus(DmsVersion.AVAILABLE_STATUS);
      sourceFolder.setOwnerID(sessionContainer.getUserRecordID());
    }//Create Copied Folder as old
    else if (DmsOperationConstant.COPY_OPERATION_AS_OLD.equals(copyFileOpt)){
      //Keep all the status as old
    }
    if (bDocumentActive) {
      //sourceFolder.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
    } else {
      if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(sourceFolder.getRecordStatus())) {
        sourceFolder.setRecordStatus(GlobalConstant.RECORD_PENDING);
      }
    }
    if(DmsDocument.COMPOUND_DOC_TYPE.equals(sourceFolder.getDocumentType())
        || DmsDocument.EMAIL_DOC_TYPE.equals(sourceFolder.getDocumentType())
        || DmsDocument.FLOW_DOC_TYPE.equals(sourceFolder.getDocumentType())
        || DmsDocument.FORM_DOC_TYPE.equals(sourceFolder.getDocumentType())) {
      newDestinationFolder = this.copyCompoundDoc(sourceFolder, destinationFolder, rootID, copyFileOpt, copyVersionOpt, bDocumentActive);
    }else if(DmsDocument.PAPER_DOC_TYPE .equals(sourceFolder.getDocumentType())){
      copiedDocument = copyDocument(sourceFolder,destinationFolder,rootID,copyFileOpt,copyVersionOpt,bDocumentActive);
      newDestinationFolder = sourceFolder;
    }else{
      newDestinationFolder = createFolder(sourceFolder);
    }

    List tempDocumentList = docRetrievalManager.getDocumentListByParentIDRootID(sourceFolder.getID(), null); // using
                                                                                                              // original
                                                                                                              // root id
    if (DmsDocument.COMPOUND_DOC_TYPE.equals(sourceFolder.getDocumentType())
        || DmsDocument.COMPOUND_DOC_TYPE.equals(sourceFolder.getDocumentType())
        || DmsDocument.EMAIL_DOC_TYPE.equals(sourceFolder.getDocumentType())
        || DmsDocument.FLOW_DOC_TYPE.equals(sourceFolder.getDocumentType())
        || DmsDocument.FORM_DOC_TYPE.equals(sourceFolder.getDocumentType())) {
      tempDocumentList = docRetrievalManager.getDocumentListByParentIDRootID(sourceFolderTemp.getID(), null); // using
                                                                                                              // original
                                                                                                              // root id
    }

    //check permission and checkout
    PermissionManager permManager = sessionContainer.getPermissionManager();
    List documentList = new ArrayList();
    if (!Utility.isEmpty(tempDocumentList)) {
      for (int i = 0; i < tempDocumentList.size(); i++) {
        DmsDocument subDocument = (DmsDocument) tempDocumentList.get(i);
        if (!DmsOperationConstant.COPY_STRUCTURE_ONLY.equals(structureOpt)) {
          // active or pennding doc will be copy, and if not permission or locked then throw exception(lee lv
          // 2006/03/30)
          if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(subDocument.getRecordStatus())
              || GlobalConstant.RECORD_PENDING.equals(subDocument.getRecordStatus())) {
            if ((DmsRoot.PERSONAL_ROOT.equals(dmsRoot.getRootType()) || permManager.hasAccessRight(conn, "D", subDocument.getID(),
                WebdavOperationManager.DMS_PERMISSION_COPY_CODE))
                && !GlobalConstant.STATUS_LOCKED.equals(subDocument.getItemStatus())) {
              documentList.add(subDocument);
            }else {
              throw new ApplicationException(DmsErrorConstant.DMS_MESSAGE_CANNOT_COPY_SUM_DOCUMENT);
            }
          }
        }else {
          if (DmsDocument.FOLDER_TYPE.equals(subDocument.getDocumentType())) {
            if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(subDocument.getRecordStatus())
                || GlobalConstant.RECORD_PENDING.equals(subDocument.getRecordStatus())) {
              if ((DmsRoot.PERSONAL_ROOT.equals(dmsRoot.getRootType()) || permManager.hasAccessRight(conn, "D", subDocument.getID(),
                  WebdavOperationManager.DMS_PERMISSION_COPY_CODE))
                  && !GlobalConstant.STATUS_LOCKED.equals(subDocument.getItemStatus())) {
                documentList.add(subDocument);
              }else {
                throw new ApplicationException(DmsErrorConstant.DMS_MESSAGE_CANNOT_COPY_SUM_DOCUMENT);
              }
            }
          }
        }
      }
    }

    if (!Utility.isEmpty(documentList)) {
      log.debug("child count: " + documentList.size());
      for (int i = 0; i < documentList.size(); i++) {
        DmsDocument subDocument = (DmsDocument) documentList.get(i);
        Integer documentIDTemp = subDocument.getID();
        if(!DmsVersion.ARCHIVED_STATUS.equals(subDocument.getItemStatus())){
          if (DmsDocument.FOLDER_TYPE.equals(subDocument.getDocumentType())
              || DmsDocument.COMPOUND_DOC_TYPE.equals(subDocument.getDocumentType())
              || DmsDocument.PAPER_DOC_TYPE.equals(subDocument.getDocumentType())
              || DmsDocument.EMAIL_DOC_TYPE.equals(subDocument.getDocumentType())
              || DmsDocument.FLOW_DOC_TYPE.equals(subDocument.getDocumentType())
              || DmsDocument.FORM_DOC_TYPE.equals(subDocument.getDocumentType())) {
            copiedDocument = copyFolder(subDocument, newDestinationFolder, rootID, copyFileOpt, copyVersionOpt, structureOpt,
                bDocumentActive);
          } //else other document type
          else {
            if(!structureOpt.equals(DmsOperationConstant.COPY_STRUCTURE_ONLY)){
              copiedDocument=copyDocument(subDocument, newDestinationFolder, rootID, copyFileOpt, copyVersionOpt, bDocumentActive);
            }
          }
        }

        //copy document details if any
        DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
        List docDetailList = docRetrievalManager.getDocumentDetailList(documentIDTemp);
        if (docDetailList != null){
          for(int ii=0 ; ii<docDetailList.size(); ii++){
            DmsDocumentDetail docDetail = (DmsDocumentDetail) docDetailList.get(ii);
            docDetail.setDocumentID(copiedDocument.getID());
            docDetail.setRecordStatus("");
            docDetail.setUpdateCount(null);
            docDetail.setCreatorID(null);
            docDetail.setCreateDate(null);
            docDetail.setUpdaterID(null);
            docDetail.setUpdateDate(null);
            docDetail = (DmsDocumentDetail)docDetailDAO.insertObject(docDetail);
          }
        }
        log.debug("created doc detail ...........");
        //end of copy document details

        //copy document index if any
        DmsDocumentIndex documentIndex = null;
        DmsDocumentIndexDAObject dmsDocumentIndexDAO = new DmsDocumentIndexDAObject(sessionContainer, conn);
        documentIndex = docRetrievalManager.getDocumentIndexByDocID(documentIDTemp);

        if (!Utility.isEmpty(documentIndex)){
          documentIndex.setDocumentID(copiedDocument.getID());
          documentIndex.setRecordStatus("");
          documentIndex.setUpdateCount(null);
          documentIndex.setCreatorID(null);
          documentIndex.setCreateDate(null);
          documentIndex.setUpdaterID(null);
          documentIndex.setUpdateDate(null);
          dmsDocumentIndexDAO.insertObject(documentIndex);
          log.debug("created doc index ...........");
        }
        //end of copy document index

      }
    }

    //copy folder; check for alert notification
    try {
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      am.call(UpdateAlert.DOCUMENT_TYPE, destinationFolder.getParentID(), UpdateAlert.CREATE_ACTION, sourceFolder.getDocumentName(), null,
          null, null, newDestinationFolder.getID());
      am.release();

      // log down in audit trail
      if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(sourceFolder.getDocumentType()))) {// barbin
                                                                                                                                    // EIP-1296
        AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
        auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, sourceFolder, AuditTrailConstant.ACCESS_TYPE_COPY_FOLDER, null);
        auditManager.release();
      }
    } catch (Exception e) {
      log.error("Error when doing audit trail", e);
    }

    docRetrievalManager.release();

    return newDestinationFolder;
  }

  /**
   * Moves the source folder to a destination folder. All the sub document(s) and sub folder(s) under source folder also
   * move.
   *
   * <pre>
   *
   * During the move,
   * the update alert is updated
   * audit trail of move operation
   *
   * </pre>
   *
   * @param sourceFolder  the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID  the destination folder rootID
   * @throws ApplicationException
   * @deprecated This method has deprecated.
   */
  public void moveFolder(DmsDocument sourceFolder, DmsDocument destinationFolder, Integer rootID) throws ApplicationException {
    this.moveFolder(sourceFolder, destinationFolder, rootID, true);
  }

  /**
   * Moves the source folder to a destination folder. All the sub document(s) and sub folder(s) under source folder also
   * move.
   *
   * <pre>
   *
   * During the move,
   * the update alert is updated
   * audit trail of move operation
   *
   * </pre>
   *
   * @param sourceFolder  the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID  the destination folder rootID
   * @param bDocumentActive true if moved folder and its sub folder(s)/document(s) record status set to active, false
   *          then set to pending
   * @throws ApplicationException
   * @deprecated This method has deprecated.
   */
  public void moveFolder(DmsDocument sourceFolder, DmsDocument destinationFolder, Integer rootID, boolean bDocumentActive)
      throws ApplicationException {
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
    DmsRootDAObject dmsRootDAObject = new DmsRootDAObject(sessionContainer,conn);

    DmsRoot dmsRoot = (DmsRoot)dmsRootDAObject.getObjectByID(sourceFolder.getRootID());
    DmsDocument originalDocument =(DmsDocument) sourceFolder.clone();
    Integer oldParentID=sourceFolder.getParentID();
    //DmsDocument originalFolder = sourceFolder;
    sourceFolder.setParentID(destinationFolder.getID());
    sourceFolder.setRootID(destinationFolder.getRootID());


    if (bDocumentActive) {
      //sourceFolder.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
    } else {
      if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(sourceFolder.getRecordStatus())) {
        sourceFolder.setRecordStatus(GlobalConstant.RECORD_PENDING);
      }
    }

    //Move Folder
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsDocument newDestinationFolder  = (DmsDocument) dmsDocumentDAO.updateObject(sourceFolder);
    //rootID = newDestinationFolder.getRootID();
    log.debug("newDestinationFolder loc = " + destinationFolder.getID());

    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDestinationFolder.getID(), DmsDocumentIndexCache.ACTION_MODE_MOVE,
        DmsDocumentIndexCache.ACTION_TYPE_UPDATE_STANDARD, originalDocument.getID());
    this.indexLUCENE(indexCache, newDestinationFolder, null, null);

    if(DmsDocument.COMPOUND_DOC_TYPE.equals(originalDocument.getDocumentType())){
      //Check for available space
      docValidateManager.checkStorageLimitAvailable(newDestinationFolder);
      log.debug("Available space exists for current document");

      // Update full text index after move document.
      // this.indexDocument(newDocument, null, GlobalConstant.OP_MODE_UPDATE, new String[]{"DOCUMENT_NAME", "ROOT_ID",
      // "PARENT_ID"});


      // handle move of physical document
      RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);

      if(originalDocument.getRootID().intValue()!=destinationFolder.getRootID().intValue()){
        DmsLocMaster sourceRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(originalDocument);
        DmsLocMaster destinationRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(destinationFolder);

        if(sourceRootLoc.getID().intValue()!= destinationRootLoc.getID().intValue()){
          if(!sourceRootLoc.getLocPath().equals(destinationRootLoc.getLocPath())){
            //move the physical document
            moveCopyPhysicalDocument(originalDocument, sourceRootLoc, destinationRootLoc, DmsOperationConstant.MOVE_OPERATION , null);
          }
        }
      }

    }


    List documentList = dmsDocumentDAO.getAllChildListByParentIDRootID(sourceFolder.getID()); //using original root id
    log.debug("child count: " + documentList.size());

    PermissionManager permManager = sessionContainer.getPermissionManager();
    for (int i = 0; i < documentList.size(); i++) {
      DmsDocument subDocument = (DmsDocument) documentList.get(i);
      // active or pennding doc will check permission and status, and if not permission or locked then exception will be
      // throw(lee lv 2006/03/30)
      if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(subDocument.getRecordStatus())
          || GlobalConstant.RECORD_PENDING.equals(subDocument.getRecordStatus())) {
        if ((!DmsRoot.PERSONAL_ROOT.equals(dmsRoot.getRootType()) && !permManager.hasAccessRight(conn, "D", subDocument.getID(),
            WebdavOperationManager.DMS_PERMISSION_MOVE_CODE))
            || GlobalConstant.STATUS_LOCKED.equals(subDocument.getItemStatus())) {
          throw new ApplicationException(DmsErrorConstant.DMS_MESSAGE_CANNOT_MOVE_SUM_DOCUMENT);
        }
      }
      if (DmsDocument.FOLDER_TYPE.equals(subDocument.getDocumentType())
          || DmsDocument.COMPOUND_DOC_TYPE.equals(subDocument.getDocumentType())) {
        moveFolder(subDocument, newDestinationFolder, rootID, bDocumentActive);
      } //move all other types of document - D, L, etc.
      else {
        moveDocument(subDocument, newDestinationFolder, rootID, true, bDocumentActive);
      }
    }

    //move folder
    try {
      AlertManager alertManager = new AlertManager(sessionContainer, conn);
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      UpdateAlert updateAlert=alertManager.getUpdateAlertByObjectTypeObjectID(UpdateAlert.DOCUMENT_TYPE,newDestinationFolder.getID());
      if(!Utility.isEmpty(updateAlert)){
        this.dealUpdateAlert(updateAlert,UpdateAlert.DELETE_ACTION);
        am.call(UpdateAlert.DOCUMENT_TYPE, newDestinationFolder.getID(), UpdateAlert.MOVE_ACTION, sourceFolder.getDocumentName(), null,
            null, null, newDestinationFolder.getID());
      }
      UpdateAlert oldParentUpdateAlert = alertManager.getUpdateAlertByObjectTypeObjectID(UpdateAlert.DOCUMENT_TYPE, oldParentID);
      if (!Utility.isEmpty(oldParentUpdateAlert)) {
        if(!this.checkSameUserSetAlert(oldParentUpdateAlert,UpdateAlert.DELETE_ACTION,updateAlert,UpdateAlert.DELETE_ACTION)){
          this.dealUpdateAlert(oldParentUpdateAlert,UpdateAlert.DELETE_ACTION);
          am.call(UpdateAlert.DOCUMENT_TYPE, oldParentID, UpdateAlert.MOVE_ACTION, sourceFolder.getDocumentName(), null, null, null,
              newDestinationFolder.getID());
        }
      }
      UpdateAlert newParentUpdateAlert = alertManager.getUpdateAlertByObjectTypeObjectID(UpdateAlert.DOCUMENT_TYPE, newDestinationFolder
          .getParentID());
      if(!Utility.isEmpty(newParentUpdateAlert)){
        if (!this.checkSameUserSetAlert(newParentUpdateAlert, UpdateAlert.CREATE_ACTION, updateAlert, UpdateAlert.DELETE_ACTION)
            && !this
                .checkSameUserSetAlert(newParentUpdateAlert, UpdateAlert.CREATE_ACTION, oldParentUpdateAlert, UpdateAlert.DELETE_ACTION)) {
          this.dealUpdateAlert(newParentUpdateAlert,UpdateAlert.CREATE_ACTION);
          am.call(UpdateAlert.DOCUMENT_TYPE, newDestinationFolder.getParentID(), UpdateAlert.MOVE_ACTION, newDestinationFolder
              .getDocumentName(), null, null, null, newDestinationFolder.getID());
        }
      }
      am.release();

      // log down in audit trail
      if (sessionContainer.getUserRecordID()!=null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(sourceFolder.getDocumentType()))) {
        AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
        auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, sourceFolder, AuditTrailConstant.ACCESS_TYPE_MOVE_FOLDER, null);
        auditManager.release();

        // Clear the permission cache of that folder.
        sessionContainer.getPermissionManager().clearPermissionCache(GlobalConstant.OBJECT_TYPE_DOCUMENT, sourceFolder.getID());
      }
    } catch (Exception e) {
      log.error("Error when doing audit trail", e);
    }
    dmsDocumentDAO=null;
  }

  /**
   * Creates a first version of the document by dmsDocument object and dmsContent object
   *
   * @param newDmsDocument the dmsDocument object
   * @param dmsContent     the dmsContent object
   * @return the new created dmsVersion object
   * @throws ApplicationException
   */
  public DmsVersion createDocumentVersion (DmsDocument newDmsDocument, DmsContent dmsContent) throws ApplicationException {
    //Create Version
    DmsVersion dmsVersion = new DmsVersion();
    dmsVersion.setDocumentID(newDmsDocument.getID());
    dmsVersion.setVersionNumber("1");
    dmsVersion.setVersionLabel(DmsOperationConstant.DMS_ROOT);
    dmsVersion.setParentID(new Integer(0));
    dmsVersion.setContentID(dmsContent.getID());
    dmsVersion.setReferenceNo(newDmsDocument.getReferenceNo()==null ? " " : newDmsDocument.getReferenceNo());
    dmsVersion.setDescription(newDmsDocument.getDescription()==null ? " " : newDmsDocument.getDescription());
    dmsVersion.setItemSize(newDmsDocument.getItemSize());
    dmsVersion.setItemStatus(DmsVersion.AVAILABLE_STATUS);
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
    DmsVersion newDmsVersion = (DmsVersion) dmsVersionDAO.insertObject(dmsVersion);
    dmsVersionDAO=null;
    return newDmsVersion;
  }

  /**
   * Update the version base on the information on the document i.e. reference no., description and document itemStatus
   *
   * @param dmsDocument the dmsDocument object
   * @param version the dmsVersion object
   * @return the Update dmsVersion object
   * @throws ApplicationException
   */
  public DmsVersion updateDocumentVersion (DmsDocument dmsDocument, String version) throws ApplicationException {
    return this.updateDocumentVersion(dmsDocument, version, null);
  }

  /**
   *  Update the target version by document and properties i.e. reference no., description and specified item status
   *
   *  @param      dmsDocument              The target document to be updated
   * @param version The (String) type indicates wether the version to be updated should be in top version or provided
   *          version.
   * @return itemStatus The (String) type indicates the status of item to be updated; NULL for target document's item
   *         status.
   *  @throws     ApplicationException     Throws when create operation fault.
   */
  public DmsVersion updateDocumentVersion (DmsDocument dmsDocument, String version, String itemStatus) throws ApplicationException {
    //Create Version
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
    DmsVersion dmsVersion = null;
    if (DmsOperationConstant.DMS_TOP_VERSION.equals(version)) {
      log.debug("Getting the top version of document "+dmsDocument.getID());
      dmsVersion =(DmsVersion) dmsVersionDAO.getTopVersionByDocumentID(dmsDocument.getID());
    } else {
      log.debug("Getting the Target version of document "+dmsDocument.getID());
      Integer versionID = TextUtility.parseIntegerObj(version);
      dmsVersion =(DmsVersion) dmsVersionDAO.getObjectByID(versionID);
    }
    dmsVersion.setReferenceNo(dmsDocument.getReferenceNo());
    dmsVersion.setDescription(dmsDocument.getDescription());
    if (itemStatus!=null) {
      dmsVersion.setItemStatus(itemStatus);
    } else {
      dmsVersion.setItemStatus(dmsDocument.getItemStatus());
    }
    log.debug("item status = "+dmsVersion.getItemStatus());
    DmsVersion newDmsVersion = (DmsVersion) dmsVersionDAO.updateObject(dmsVersion);
    dmsVersionDAO=null;
    return newDmsVersion;
  }

  /**
   * Update the target version's BK_ARCHIVE_ID by specified archived id and archive type It also updates version
   * reference no., description and item Status by document's version reference no., description and item Status if it
   * is the archive operation and the version is the top version, the dmsDocuemnt itemStatus will also be update as
   * DmsVersion.ARCHIVED_STATUS. If it is the archive operation, all the version's item status will update as
   * DmsVersion.ARCHIVED_STATUS.
   *
   * @param dmsDocument the dmsDocument object for updating the version
   * @param version  the version id or top version specified for update
   * @param archiveID the archive ID that update to the version
   * @param archiveType if it is Archive operation, then update the items status as DmsVersion.ARCHIVED_STATUS
   * @return the update Dmsversion object
   * @throws ApplicationException
   */
  public DmsVersion archiveDocumentVersion(DmsDocument dmsDocument, String version, Integer archiveID, String archiveType)
      throws ApplicationException {
    //update archive id and item status of a Version
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);

    DmsVersion dmsVersion = null;
    if (DmsOperationConstant.DMS_TOP_VERSION.equals(version)) {
      log.debug("Getting the top version of document "+dmsDocument.getID());
      dmsVersion =(DmsVersion) dmsVersionDAO.getTopVersionByDocumentID(dmsDocument.getID());
    } else {
      log.debug("Getting the Target version of document "+dmsDocument.getID());
      Integer versionID = TextUtility.parseIntegerObj(version);
      dmsVersion =(DmsVersion) dmsVersionDAO.getObjectByID(versionID);
    }
    dmsVersion.setReferenceNo(dmsDocument.getReferenceNo());
    dmsVersion.setDescription(dmsDocument.getDescription());
    dmsVersion.setBkArchiveID(archiveID);
    //log.debug("backup archive id = "+dmsVersion.getBkArchiveID());
    if (DmsArchive.ARCHIVE_TYPE.equals(archiveType)) {
      dmsVersion.setItemStatus(DmsVersion.ARCHIVED_STATUS);
      dmsDocument.setItemStatus(DmsVersion.ARCHIVED_STATUS);
      DmsVersion topVersion = (DmsVersion) dmsVersionDAO.getTopVersionByDocumentID(dmsDocument.getID());
      if (topVersion.getID().equals(dmsVersion.getID()) ) { // update the dms document when it is the active version
        DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
        dmsDocument = (DmsDocument) dmsDocumentDAO.updateObject(dmsDocument);
      }
    }
    DmsVersion newDmsVersion = (DmsVersion) dmsVersionDAO.updateObject(dmsVersion);
    dmsVersionDAO=null;
    return newDmsVersion;
  }


  /**
   * Restore the version if the version is archived.
   * <P>
   * The version and the corresponding document item status is restored
   * </P>
   *
   * @param documentID the dmsDocument object id
   * @param versionID the dmsVersion object ID
   * @return the update dmsVersion object
   * @throws ApplicationException
   */
  public DmsVersion restoreDocumentVersion (Integer documentID, Integer versionID) throws ApplicationException {
    //update archive id and item status of a Version
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);

    DmsDocument dmsDocument = (DmsDocument) dmsDocumentDAO.getObjectByID(documentID);
    DmsVersion dmsVersion = (DmsVersion) dmsVersionDAO.getObjectByID(versionID);
    DmsVersion topVersion = (DmsVersion) dmsVersionDAO.getTopVersionByDocumentID(documentID);

    String versionItemStatus = "";
    if (topVersion!=null && topVersion.getID().equals(versionID)) {
      versionItemStatus = DmsVersion.AVAILABLE_STATUS;
    } else {
      versionItemStatus = DmsVersion.EXCLUSIVE_LOCK;
    }

    dmsVersion.setBkArchiveID(null);
    dmsVersion.setItemStatus(versionItemStatus);
    dmsDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);

    dmsDocumentDAO.updateObject(dmsDocument);

    //restore archive file is considered to update operation then send alert
    AdapterMaster am = new AdapterMaster(sessionContainer, conn);
    am.call(UpdateAlert.DOCUMENT_TYPE, dmsDocument.getID(), UpdateAlert.UPDATE_ACTION, dmsDocument.getDocumentName(),
        null, null, null, dmsDocument.getID());
    am.release();

    DmsVersion newDmsVersion = (DmsVersion) dmsVersionDAO.updateObject(dmsVersion);
    dmsVersionDAO=null;
    dmsDocumentDAO=null;
    return newDmsVersion;
  }

  /**
   * Create a relationship of a document and version
   *
   * @param newDmsDocument the dmsDocument object
   * @param newDmsVersion the dmsVersion object
   * @return the MtmDocumentVersion Object
   * @throws ApplicationException
   */
  public MtmDocumentVersion createDocumentVersionRelationship(DmsDocument newDmsDocument, DmsVersion newDmsVersion)
      throws ApplicationException {
    //Create Relationship
    MtmDocumentVersion mtmDocumentVersion = new MtmDocumentVersion();
    mtmDocumentVersion.setDocumentID(newDmsDocument.getID());
    mtmDocumentVersion.setVersionID(newDmsVersion.getID());
    MtmDocumentVersionDAObject mtmDocumentVersionDAO = new MtmDocumentVersionDAObject(sessionContainer, conn);
    mtmDocumentVersion=(MtmDocumentVersion) mtmDocumentVersionDAO.insertObject(mtmDocumentVersion);
    mtmDocumentVersionDAO=null;
    return mtmDocumentVersion;
  }

  /**
   * Creates a document relationship to a related document
   *
   * update the update alert if the relationship is set and record in audit trail
   *
   * @param docRelationship the MtmDocumentRelationship object
   * @param relatedDocument the related dmsDocument object
   * @return the MtmDocumentRelationship object
   * @throws ApplicationException
   */
  public MtmDocumentRelationship createDocumentRelationship(MtmDocumentRelationship docRelationship, DmsDocument relatedDocument)
      throws ApplicationException {
    //Create Relationship
    docRelationship.setRelatedDocumentID(relatedDocument.getID());
    MtmDocumentRelationshipDAObject mtmDocumentRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    docRelationship =  (MtmDocumentRelationship) mtmDocumentRelationshipDAO.insertObject(docRelationship);
    mtmDocumentRelationshipDAO=null;

    /* Create Document Relatioship; check for alert notification */
    if (relatedDocument.getParentID().intValue() != 0) {
      DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
      DmsDocument parentDoc = (DmsDocument) dmsDocumentDAO.getObjectByID(relatedDocument.getParentID());
      dmsDocumentDAO=null;
      try {
        AdapterMaster am = new AdapterMaster(sessionContainer, conn);
        am.call(UpdateAlert.DOCUMENT_TYPE, parentDoc.getID(), UpdateAlert.CREATE_SHORTCUT_ACTION, relatedDocument.getDocumentName(), null,
            null, null, relatedDocument.getID());
        am.release();
      } catch (Exception e) {
        log.error("Error when doing alert", e);
      }
    }

    // log down in audit trail
    if(DmsDocument.DOCUMENT_LINK.equals(docRelationship.getRelationshipType())){
      relatedDocument.setID(docRelationship.getDocumentID());
    }
    if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(relatedDocument.getDocumentType()))) {// barbin
                                                                                                                                      // EIP-1296
      AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, relatedDocument, AuditTrailConstant.ACCESS_TYPE_CREATE_SHORTCUT, "1");
      auditManager.release();
    }
    mtmDocumentRelationshipDAO=null;
    return docRelationship;
  }

  /**
   * Update the document relationship with a related document
   *
   * update the update alert if the relationship is set and record in audit trail
   *
   * @param docRelationship the MtmDocumentRelatinship Object
   * @param relatedDocument the related DmsDocument object
   * @return
   * @throws ApplicationException
   */
  public MtmDocumentRelationship updateDocumentRelationship(MtmDocumentRelationship docRelationship, DmsDocument relatedDocument)
      throws ApplicationException {
    //Create Relationship
    docRelationship.setRelatedDocumentID(relatedDocument.getID());
    MtmDocumentRelationshipDAObject mtmDocumentRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    docRelationship =  (MtmDocumentRelationship) mtmDocumentRelationshipDAO.updateObject(docRelationship);
    mtmDocumentRelationshipDAO=null;

    /* Create Document Relatioship; check for alert notification */
    if (relatedDocument.getParentID().intValue() != 0) {
      DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
      DmsDocument parentDoc = (DmsDocument) dmsDocumentDAO.getObjectByID(relatedDocument.getParentID());
      dmsDocumentDAO=null;
      try {
        AdapterMaster am = new AdapterMaster(sessionContainer, conn);
        am.call(UpdateAlert.DOCUMENT_TYPE, parentDoc.getID(), UpdateAlert.UPDATE_ACTION, relatedDocument.getDocumentName(), null, null,
            null, relatedDocument.getID());
        am.release();
      } catch (Exception e) {
        log.error("Error when doing alert", e);
      }
    }

    // log down in audit trail
    if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(relatedDocument.getDocumentType()))){
      AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, relatedDocument, AuditTrailConstant.ACCESS_TYPE_UPDATE, "1");
      auditManager.release();
    }
    return docRelationship;
  }

  /**
   * Removes a document relationship with a related document
   *
   * update the update alert if the relationship is set and record in audit trail
   *
   * @param docRelationshipID the MtmDocumentRelationship object ID
   * @param relatedDocument the related DmsDocument object
   * @return the MtmDocumentRelationship object
   * @throws ApplicationException
   */
  public MtmDocumentRelationship deleteDocumentRelationship(Integer docRelationshipID, DmsDocument relatedDocument)
      throws ApplicationException {


    //Delete relationship
    MtmDocumentRelationshipDAObject mtmDocumentRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    MtmDocumentRelationship docRelationship = (MtmDocumentRelationship) mtmDocumentRelationshipDAO.deleteObjectByID(docRelationshipID);

    mtmDocumentRelationshipDAO=null;

    /* Delete Document Relatioship; check for alert notification */
    if (relatedDocument.getParentID().intValue() != 0) {
      DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
      DmsDocument parentDoc = (DmsDocument) dmsDocumentDAO.getObjectByID(relatedDocument.getParentID());
      try {
        AdapterMaster am = new AdapterMaster(sessionContainer, conn);
        am.call(UpdateAlert.DOCUMENT_TYPE, parentDoc.getID(), UpdateAlert.DELETE_SHORTCUT_ACTION, relatedDocument.getDocumentName(), null,
            null, null, relatedDocument.getID());
        am.release();
      } catch (Exception e) {
        log.error("Error when doing alert", e);
      }
      dmsDocumentDAO=null;
    }

    // log down in audit trail
    if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(relatedDocument.getDocumentType()))) {// barbin
                                                                                                                                      // EIP-1296
      AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, relatedDocument, AuditTrailConstant.ACCESS_TYPE_DELETE_SHORTCUT, "1");
      auditManager.release();
    }

    return docRelationship;
  }

  /**
   * Creates a DmsDocumentDetail object of user defined field detail
   *
   * @param documentDetail the DmsDocumentDetail object
   * @return the created DmsDocumentDetail object
   * @throws ApplicationException
   */
  public DmsDocumentDetail createDocumentDetail(DmsDocumentDetail documentDetail) throws ApplicationException {
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    DmsDocumentDetail docDetail = (DmsDocumentDetail) docDetailDAO.insertObject(documentDetail);
    docDetailDAO = null;
    return docDetail;
  }

  /**
   * Updates a DmsDocumentDetail Object of user defined field detail
   *
   * @param documentDetail the DmsDocumentDetail object
   * @return the updated DmsDocumentDetail object
   * @throws ApplicationException
   */
  public DmsDocumentDetail updateDocumentDetail(DmsDocumentDetail documentDetail) throws ApplicationException {
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    DmsDocumentDetail docDetail = (DmsDocumentDetail) docDetailDAO.updateObject(documentDetail);
    docDetailDAO=null;
    return docDetail;
  }

  /**
   * Deletes a user defined field detail by user defined field ID
   *
   * @param udfID the user defined field ID
   * @throws ApplicationException
   */
  public void deleteDocumentDetailByUDFID(Integer udfID) throws ApplicationException {
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    docDetailDAO.deleteByUDFID(udfID);
    docDetailDAO=null;
  }

  /**
   * Deletes a given user defined field detail
   *
   * @param documentDetail the DmsDocumentDetail object to be deleted
   * @throws ApplicationException
   */
  public void deleteDocumentDetail(DmsDocumentDetail documentDetail) throws ApplicationException {
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    docDetailDAO.deleteObject(documentDetail);
    docDetailDAO=null;
  }

  /**
   * Deletes a user defined field detail by dmsDocuemnt object ID
   *
   * @param docID the DmsDocument object ID
   * @throws ApplicationException
   */
  public void deleteDocumentDetailByDocumentID(Integer docID)  throws ApplicationException {
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    docDetailDAO.deleteByDocumentID(docID);
    docDetailDAO=null;
  }

  /**
   * Index the document to db storage
   *
   * <PRE>
   *
   * Mode: GlobalConstant.OP_MODE_INSERT - create of new index GlobalConstant.OP_MODE_UPDATE - update the existing index
   * GlobalConstant.OP_MODE_DELETE - remove the indexes
   *
   * </PRE>
   *
   * @param dmsDocument the DmsDocument object
   * @param mode the mode of operation
   * @throws ApplicationException
   * @deprecated This method has deprecated.
   */
  public void indexToDB(DmsDocument dmsDocument,String mode) throws ApplicationException {
    // during index the document by lucene, also update the user define detail to
    // DMS_DOCUMENT_INDEX begin
    DmsDocumentIndex documentIndex = null;
    DmsDocumentIndex newDocumentIndex = new DmsDocumentIndex();
    DmsDocumentIndexDAObject dmsDocumentIndexDAO = new DmsDocumentIndexDAObject(sessionContainer, conn);
    DocumentRetrievalManager retrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    documentIndex = retrievalManager.getDocumentIndexByDocID(dmsDocument.getID());
    newDocumentIndex.setDocumentID(dmsDocument.getID());

    Integer noOfIndex = SystemParameterFactory.getSystemParameterInteger(SystemParameterConstant.DMS_MAX_INDEX_FIELDS);

    try {
      List docDetailList =  dmsDocument.getDocumentDetails();
      if (Utility.isEmpty(docDetailList)){
        docDetailList=retrievalManager.getDocumentDetailList(dmsDocument.getID());
        dmsDocument.setDocumentDetails(docDetailList);
        if(!Utility.isEmpty(docDetailList)){
          //DmsDocumentDetail tmpDetail = (DmsDocumentDetail)docDetailList.get(0);
          dmsDocument.setUserDefinedFieldID(((DmsDocumentDetail)docDetailList.get(0)).getUserDefinedFieldID());
        }
      }
      docDetailList =retrievalManager.sortDocDetailList(docDetailList);

      if (!Utility.isEmpty(docDetailList)) {

        for (int i = 1; i <= docDetailList.size() && i <= noOfIndex.intValue(); i++) {
          newDocumentIndex.setUserDefinedFieldID(dmsDocument.getUserDefinedFieldID());
          Method setIndex = newDocumentIndex.getClass().getMethod("setIndex" + i, new Class[] {String.class});
          String[] arg = new String[1];
          arg[0] = null;
          /* convert the value of document profile field into full text type */
          DmsDocumentDetail dmsDocDetail = (DmsDocumentDetail)docDetailList.get(i - 1);
          if (!Utility.isEmpty(dmsDocDetail.getFieldValue()) || dmsDocDetail.getDateValue() != null
              || dmsDocDetail.getToDateValue() != null || dmsDocDetail.getNumericValue() != null
              || dmsDocDetail.getToNumericValue() != null) {
            if (!Utility.isEmpty(dmsDocDetail.getFieldValue())) {
              arg[0] = dmsDocDetail.getFieldValue();
            } else if (!Utility.isEmpty(dmsDocDetail.getNumericValue())) {
              arg[0] = com.dcivision.framework.IndexManager.numberPad(dmsDocDetail.getNumericValue());
            } else if (!Utility.isEmpty(dmsDocDetail.getDateValue())) {
             // arg[0] = DateField.dateToString(dmsDocDetail.getDateValue());
             arg[0] = TextUtility.formatTimestampToIndex(dmsDocDetail.getDateValue());
            }


          setIndex.invoke(newDocumentIndex, arg);

          } //end if


        } //end for

        if (docDetailList.size() > 0) {
          if (documentIndex == null) {

            dmsDocumentIndexDAO.insertObject(newDocumentIndex);
          } else {
            if(!DmsOperationConstant.MOVE_OPERATION.equals(mode)){
              newDocumentIndex.setUpdateCount(documentIndex.getUpdateCount());
              dmsDocumentIndexDAO.updateByDocID(newDocumentIndex);
            }
          }
        }
      }else{
        //cater for the update from having profile to empty profile
        if(!DmsOperationConstant.MOVE_OPERATION.equals(mode)){
          dmsDocumentIndexDAO.deleteByDocID(dmsDocument.getID());
        }

      }
    } catch (Exception e) {
      log.error("Error during index document", e);
      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
    }
  }

  /**
   * copy the standard profile copy the reference no, description and default profile
   *
   * <PRE>
   *
   * if the destination document(s) is shortcut, the description of the source document will not be copied.
   *
   * </PRE>
   *
   * @param sourceDoc              copy source of dmsDocument
   * @param alertEditID            destination of dmsDocument
   *
   */

  public DmsDocument copyStandardProfile(DmsDocument sourceDoc, DmsDocument destinateDoc)throws ApplicationException{
      destinateDoc.setReferenceNo(sourceDoc.getReferenceNo());
      if(!DmsDocument.DOCUMENT_LINK.equals(destinateDoc.getDocumentType())){
        destinateDoc.setDescription(sourceDoc.getDescription());
      }
    int totalFieldCount = Integer.parseInt(com.dcivision.framework.SystemParameterFactory
        .getSystemParameter(com.dcivision.framework.SystemParameterConstant.DMS_DEFAULT_PROFILE_FIELD_COUNT));

      try{
        for(int i=1;i<=totalFieldCount;i++){
          String[] arg = new String[1];
          arg[0] = null;
          Method setUserDefine = destinateDoc.getClass().getMethod("setUserDef" + i, new Class[] {String.class});
          Method getUserDefine = sourceDoc.getClass().getMethod("getUserDef" + i, null);
          arg[0]=(String)getUserDefine.invoke(sourceDoc,null);
          setUserDefine.invoke(destinateDoc, arg);
        }
      }catch(Exception e){
        log.error("Error during index document", e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      }
      return destinateDoc;
  }


  /**
   * setAlertEditID, update alert edit ID in the DMS_DOCUMENT table
   *
   * @param ID the dmsDocument object ID
   * @param alertEditID the alertEditID to be updated
   * @throws ApplicationException
   */
  public void setAlertEditID(Integer ID, Integer alertEditID) throws ApplicationException {
    String sAlertEditID = alertEditID == null ? null : alertEditID.toString();
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsDocument doc = (DmsDocument)dmsDocumentDAO.getObjectByID(ID);
    dmsDocumentDAO.documentSQLExecute("UPDATE", "ALERT_EDIT_ID", sAlertEditID, doc, false); // EIP-1438 07/01/11 LEE not
                                                                                            // update updator
    dmsDocumentDAO = null;
  }

  /**
   * setAlertInviteID, update alert invite ID in the DMS_DOCUMENT table
   *
   * @param ID the dmsDocument object ID
   * @param alertInviteID the alert invite ID
   * @throws ApplicationException
   */
  public void setAlertInviteID(Integer ID, Integer alertInviteID) throws ApplicationException {
    String sAlertInviteID = alertInviteID == null? null : alertInviteID.toString();
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsDocument doc = (DmsDocument)dmsDocumentDAO.getObjectByID(ID);
    dmsDocumentDAO.documentSQLExecute("UPDATE", "ALERT_INVITE_ID", sAlertInviteID, doc, false); // EIP-1438 07/01/11 LEE
                                                                                                // not update updator
    dmsDocumentDAO = null;
  }

  /**
   * Generates key based on the SysUserDefinedIndex object, if the targetField is specified as reference no, the
   * dmsDocument object reference no will be updated as the key generated. The generated will auto incremented and
   * update back to the SysUserDefinedIndex for next key generation
   *
   * @param document the dmsDocument object
   * @param udfIndexID sysUserDefinedIndex object ID
   * @param targetField the target field in the DmsDocument object to updated as the generated key
   * @return the dmsDocument object if reference no is update, if no update just return the dmsDocument without updated
   * @throws ApplicationException
   */
  private DmsDocument udfAutoGenerateValidation(DmsDocument document, Integer udfIndexID, String targetField) throws ApplicationException {
    String autoGenerateKey = "";
    SysUserDefinedIndexDAObject udfDAO = new SysUserDefinedIndexDAObject(sessionContainer, conn);
    SysUserDefinedIndex udfIndex = (SysUserDefinedIndex) udfDAO.getObjectByID(udfIndexID);
    String template = udfIndex.getGenKeyTemplate();
    Integer maxNumber = udfIndex.getGenKeyNumMax()!=null ? udfIndex.getGenKeyNumMax() : new Integer("0");

    // create physical file
    try {
      this.labelGenerator = (AutoLabelGenerator) Class.forName(
          SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_UDF_AUTO_GENERATOR_CLASS)).newInstance();
    } catch (Exception e) {
      log.error("Label generator class not found.", e);
      throw new ApplicationException(DmsErrorConstant.LABEL_GENERATOR_CLASS_NOT_FOUND);
    }

    autoGenerateKey = labelGenerator.process(template, maxNumber);
    log.debug("autoGenerateKey = " + autoGenerateKey);
    if ("REFERENCE_NO".equals(targetField)){
      document.setReferenceNo(autoGenerateKey);
    }
    String nextNumber = TextUtility.formatInteger(maxNumber.intValue() + 1);
    udfDAO.updateFieldValue(udfIndex, "GEN_KEY_NUM_MAX", nextNumber);
    log.debug("document ref = " + document.getReferenceNo());
    udfDAO=null;
    return document;
  }

  /**
   * creates the new UDF if required, return the documentDetail List for further opertaion.
   *
   * <PRE>
   *
   * This method get the scan upload index xml file and parse into list of documentDetail object
   *
   * </PRE>
   *
   * @param udfMap  Map the store list of the User defined field Name SysUserDefinedIndexDetail object
   * @param indexFile the upload XML document object with user defined name and value
   * @throws ApplicationException
   * @see com.dcivision.framework.bean.SysUserDefinedIndexDetail;
   */
  public List createUploadedDocumentUDF (Map udfMap, org.w3c.dom.Document indexFile) throws ApplicationException{
    Integer udfID;
    Map udfDetailMap = new HashMap();
    Map udfDetailTypeMap = new HashMap();
    List docDetailList = new ArrayList();

    SysUserDefinedIndexDAObject userDefinedFieldDAO = new SysUserDefinedIndexDAObject(sessionContainer, conn);
    SysUserDefinedIndexDetailDAObject userDefinedFieldDetailDAO = new SysUserDefinedIndexDetailDAObject(sessionContainer, conn);

    //check duplicate udf name
    SysUserDefinedIndex sysUserDefinedIndex = (SysUserDefinedIndex)udfMap.get("SysUserDefinedIndex");
    List udfDetailList = (List) udfMap.get("udfDetailList");
    udfID = userDefinedFieldDAO.getUDFIDByTypeName(sysUserDefinedIndex.getUserDefinedType());

    if (udfID==null) {
      if(!Utility.isEmpty(sysUserDefinedIndex.getUserDefinedType())){
        //Create new udf and udf Detail; using default parsed field type "String"
        sysUserDefinedIndex = (SysUserDefinedIndex)userDefinedFieldDAO.insertObject(sysUserDefinedIndex);
        udfID = sysUserDefinedIndex.getID();
        for (int i=0; i<udfDetailList.size(); i++){
          SysUserDefinedIndexDetail sysUserDefinedIndexDetail = (SysUserDefinedIndexDetail)udfDetailList.get(i);
          sysUserDefinedIndexDetail.setUserDefinedID(sysUserDefinedIndex.getID());
          sysUserDefinedIndexDetail = (SysUserDefinedIndexDetail)userDefinedFieldDetailDAO.insertObject(sysUserDefinedIndexDetail);
          udfDetailMap.put(sysUserDefinedIndexDetail.getFieldName(), sysUserDefinedIndexDetail.getID());
          udfDetailTypeMap.put(sysUserDefinedIndexDetail.getID(), sysUserDefinedIndexDetail.getFieldType());
        }
      }
    }else{
      //Get udf Detail
      for (int i=0; i<udfDetailList.size(); i++){
        SysUserDefinedIndexDetail sysUserDefinedIndexDetail = (SysUserDefinedIndexDetail)udfDetailList.get(i);
        sysUserDefinedIndexDetail = (SysUserDefinedIndexDetail) userDefinedFieldDetailDAO.getObjectByName(udfID, sysUserDefinedIndexDetail
            .getFieldName());
        Integer tmpIndexDetailID = null;
        String tmpFieldType = "";
        if (sysUserDefinedIndexDetail!=null){
          tmpIndexDetailID = sysUserDefinedIndexDetail.getID();
          tmpFieldType = sysUserDefinedIndexDetail.getFieldType();

          udfDetailMap.put(sysUserDefinedIndexDetail.getFieldName(), tmpIndexDetailID);
          udfDetailTypeMap.put(sysUserDefinedIndexDetail.getID(), tmpFieldType);

        } else {
          tmpIndexDetailID = null;
          tmpFieldType="";
        }
       }
    }
    userDefinedFieldDAO=null;
    userDefinedFieldDetailDAO=null;

    //Document Detail - fields
    NodeList fieldList = indexFile.getElementsByTagName("field");
    for (int i=0; i<fieldList.getLength(); i++){
      DmsDocumentDetail dmsDocumentDetail = new DmsDocumentDetail();
      dmsDocumentDetail.setUserDefinedFieldID(udfID);
      Element targetNode = (Element)fieldList.item(i);
      String fieldName = targetNode.getAttribute("name");
      Integer udfDetailID = (Integer)udfDetailMap.get(fieldName);
      if (udfDetailID != null) {
        dmsDocumentDetail.setUserDefinedFieldDetailID(udfDetailID);

        //get the text as subnode handling
        Node subnode = fieldList.item(i).getFirstChild();
        String fieldValue = "";
        if (subnode != null) {
          fieldValue = subnode.getNodeValue();
          if(!Utility.isEmpty(fieldValue) && fieldValue.length()>255){
            fieldValue=fieldValue.substring(0,254);
          }
          log.debug("value " + fieldValue);
        }
        String fieldType = (String)udfDetailTypeMap.get(udfDetailID);
//log.debug("fieldType = " + fieldType);
        if (SysUserDefinedIndexDetail.DATE_FIELD.equals(fieldType) && !Utility.isEmpty(fieldValue)) {
          String scanDateFormat = SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_SCAN_DATE_FORMAT);
          java.sql.Timestamp date = Utility.parseDateStringToSystemDate(fieldValue, scanDateFormat);
          //java.sql.Timestamp date = TextUtility.parseTimestamp(fieldValue);
          if (date != null) {
            dmsDocumentDetail.setDateValue(date);
//log.debug("fieldType D= " +  dmsDocumentDetail.getDateValue());
          }
        } //Numeric type
        else if (SysUserDefinedIndexDetail.NUMBER_FIELD.equals(fieldType)) {
          dmsDocumentDetail.setNumericValue(TextUtility.parseDoubleObj(fieldValue));
//log.debug("fieldType N= " +  dmsDocumentDetail.getNumericValue());
        } //String type
        else if (SysUserDefinedIndexDetail.STRING_FIELD.equals(fieldType)) {
          dmsDocumentDetail.setFieldValue(fieldValue);
        } else {
          dmsDocumentDetail.setFieldValue(fieldValue);
//log.debug("fieldType S= " +  dmsDocumentDetail.getFieldValue());
        }

        dmsDocumentDetail.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
        docDetailList.add(dmsDocumentDetail);
      }
    }
//    log.debug("parsed doc detail list = " +docDetailList.size());
    return docDetailList;
  }


  /**
   *  Create and reterive the new DmsArchiveDetail object
   *
   *  @param      archiveDetail            The object of DmsArchiveDetail
   *  @return     DmsArchiveDetail         The (DmsArchiveDetail) of object created.
   *  @throws     ApplicationException     Throws when create operation fault.
   */
  public DmsArchiveDetail createArchiveDetail(DmsArchiveDetail archiveDetail) throws ApplicationException {
    DmsArchiveDetailDAObject archiveDetailDAO = new DmsArchiveDetailDAObject(sessionContainer, conn);
    DmsArchiveDetail newArchiveDetail = (DmsArchiveDetail) archiveDetailDAO.insertObject(archiveDetail);
    archiveDetailDAO=null;
    return newArchiveDetail;
  }

  /**
   * Get the string array from the default profile setting which used for the options shown in select menu.
   *
   * <PRE>
   *
   * This method gets option values of the default profile field type
   * DmsDefaultProfileSetting.FIELD_TYPE_SELECT_DATABASE The return 2D string array as following: first dimension array [] -
   * row of option sedcond dimesion array[] - a array with 2 element [0] - null value [1] - option value
   *
   * </PRE>
   *
   * @param profSetting    Default DMS profile.
   * @return               2D string array.
   */
  public String[][] getOptionStringArray(DmsDefaultProfileSetting profSetting) throws ApplicationException {
    String[][] result = null;

    if (DmsDefaultProfileSetting.FIELD_TYPE_SELECT_DATABASE.equals(profSetting.getFieldType())) {
      java.sql.PreparedStatement preStat = null;
      java.sql.ResultSet rs = null;
      try {
        preStat = conn.prepareStatement(profSetting.getSqlStat());
        rs = preStat.executeQuery();
        List tmpList = new ArrayList();
        while (rs.next()) {
          String[] row = new String[2];
          //update by beyond ,for EIP-2115
          row[0] = null;
          row[1] = rs.getString(1);
          //update end
          tmpList.add(row);
        }
        result = new String[tmpList.size()][];
        for (int i = 0; i < tmpList.size(); i++) {
          result[i] = (String[])tmpList.get(i);
        }
      } catch (Exception e) {
        log.error("Error when get data by Profile SQL statement.", e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
      }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
    }
      }
    }

    return(result);
  }

  /**
   * Get the string array from the SYS_USER_DEFINED_DETAIL which used for the options shown in select menu.
   *
   * <PRE>
   *
   * This method gets the option values of the SysUserDefinedIndexDetail that the field type is
   * DmsDefaultProfileSetting.FIELD_TYPE_SELECT_DATABASE
   *
   * The return String array which give the option value for selection.
   *
   * </PRE>
   *
   * @param sysUserDefinedDetail    UDF Detail.
   * @return               string array of select option.
   */
  public String[] getUDFOptionStringArray(SysUserDefinedIndexDetail sysUserDefinedDetail) throws ApplicationException {
    String[] result = null;

    if (DmsDefaultProfileSetting.FIELD_TYPE_SELECT_DATABASE.equals(sysUserDefinedDetail.getFieldType())) {
      java.sql.PreparedStatement preStat = null;
      java.sql.ResultSet rs = null;
      try {
        preStat = conn.prepareStatement(sysUserDefinedDetail.getSqlStat());
        preStat.setInt(1, sysUserDefinedDetail.getID().intValue());
        rs = preStat.executeQuery();
        List tmpList = new ArrayList();
        while (rs.next()) {
          String value = "";
          value = rs.getString(1);
          tmpList.add(value);
        }
        result = new String[tmpList.size()+1];
        result[0] = MessageResourcesFactory.getMessage(sessionContainer.getSessionLocale(), "common.options.select_menu.select_one");
        for (int i = 0; i < tmpList.size(); i++) {
          result[i+1] = (String)tmpList.get(i);
        }
      } catch (Exception e) {
        log.error("Error when get data by Profile SQL statement.", e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
      }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
    }
      }
    }

    return(result);
  }


  /**
   * Send the Document as Email attachment
   *
   * @param sender  temporary no use
   * @param email the DmsSendEmail email object
   * @param document  the dmsDocument object, its physical file as attachement
   * @param version   the version object, to get the correct version physical file as attachment
   * @return State of the email send, DmsOperationConstant.EMAIL_SENT if success
   */
  public String sendDocumentByEmailAttachement(String sender, DmsSendEmail email, DmsDocument document, String version)
      throws ApplicationException {
    String state = "";
    InputStream dataStream=null;

    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);

    try {
      // create an email
      EmailDeliveryMessage msg = new EmailDeliveryMessage();

      String curUserEmail = UserInfoFactory.getUserEmailAddress(sessionContainer.getUserRecordID());
      if (Utility.isEmpty(curUserEmail)) {
        curUserEmail = SystemParameterFactory.getSystemParameter(SystemParameterConstant.SMTP_ADMIN_ADDRESS);
      }
      String curUserName = UserInfoFactory.getUserFullName(sessionContainer.getUserRecordID());
      if (Utility.isEmpty(curUserName)) {
        curUserName = SystemParameterFactory.getSystemParameter(SystemParameterConstant.SMTP_ADMIN_NAME);
      }
      msg.setSender(new GenericAddress("", curUserName,"utf-8"));//barbin 2006-7-10

      if(!Utility.isEmpty(email.getRecipients())){
      String[] toRecipients = TextUtility.splitString(email.getRecipients(), ";");
        for (int i = 0; i < toRecipients.length; ++i) {
          msg.addToRecipient(new GenericAddress(toRecipients[i]));
        }
      }
      if (!Utility.isEmpty(email.getCCRecipients())) {
        String[] ccRecipients = TextUtility.splitString(email.getCCRecipients(), ";");
        for (int i = 0; i < ccRecipients.length; ++i) {
          msg.addCCRecipient(new GenericAddress(ccRecipients[i]));
        }
      }
      if (!Utility.isEmpty(email.getBCCRecipients())) {
        String[] bccRecipients = TextUtility.splitString(email.getBCCRecipients(), ";");
        for (int i = 0; i < bccRecipients.length; ++i) {
          msg.addBCCRecipient(new GenericAddress(bccRecipients[i]));
        }
      }
      msg.setCharset(SystemParameterFactory.getSystemParameter(SystemParameterConstant.ENCODING));
      msg.setSubject(email.getSubject());
      msg.setMailContent(Utility.isEmpty(email.getContent())?"":email.getContent());

      // add attachment
      Integer documentID = document.getID();
      Integer versionID = new Integer(1);
      DmsVersion dmsVersion = new DmsVersion();
      Integer contentID = new Integer(0);
      if (!Utility.isEmpty(version) && !DmsOperationConstant.DMS_TOP_VERSION.equals(version)) {
        versionID = TextUtility.parseIntegerObj(version);
        dmsVersion = docRetrievalManager.getVersionByVersionID(versionID);
        contentID = dmsVersion.getContentID();
      } else {
        dmsVersion = docRetrievalManager.getTopVersionByDocumentID(documentID);
        contentID = dmsVersion.getContentID();
      }

      /* Check for document link attachement */
      if (DmsDocument.DOCUMENT_LINK.equals(document.getDocumentType())) {
        MtmDocumentRelationshipDAObject docRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
        Integer targetDocID = docRelationshipDAO.getTargetDocIDByRelatedDocID(document.getID(), document.getDocumentType());
        DmsDocument targetDoc = docRetrievalManager.getDocument(targetDocID);
        /* Used to update the doc link name and type; Wont infulence the getDocumentProfileInfo() */
        targetDoc.setDocumentName(document.getDocumentName());
        targetDoc.setDocumentType(document.getDocumentType());
        //update the doc ID for shortcut linkage
        documentID = targetDocID;
        document = targetDoc;

        //update the real link document version
        dmsVersion = docRetrievalManager.getTopVersionByDocumentID(documentID);
        contentID = dmsVersion.getContentID();
        docRelationshipDAO=null;
      }
      /*End the Document link attachement handling */
      if(!DmsDocument.FOLDER_TYPE.equals(document.getDocumentType()) && !DmsDocument.PAPER_DOC_TYPE.equals(document.getDocumentType())){
        DmsContent docContent = docRetrievalManager.getContentByContentID(contentID);

        dataStream  = dmsContentManager.readDmsDocumentStoreContent(document,docContent);

        if(DmsDocument.COMPOUND_DOC_TYPE.equals(document.getDocumentType())
                || DmsDocument.EMAIL_DOC_TYPE.equals(document.getDocumentType())){
              String zipFilePath=docRetrievalManager.getCompoundZip(document).toString();
            dataStream=new FileInputStream(zipFilePath);
            msg.addAttachment(new File(zipFilePath).getName(), dataStream);
            }else{
              msg.addAttachment(document.getDocumentName(), dataStream);
            }

        String contentType=HTTPUtility.getContentType(document.getDocumentName());
        msg.setContentType(contentType);
      }
      // send email
      NotificationWay emailNotification = NotificationWayFactory.getNotificationInstance(NotificationWay.EMAIL_NOTIFICATION_INSTANCE);
      emailNotification.addDeliveryMessage(msg);
      if( ! emailNotification.send()) {
        throw new ApplicationException(DmsErrorConstant.ERROR_DMS_SEND_EMAIL);
      }
      state=DmsOperationConstant.EMAIL_SENT;
      log.debug("---------------Message Send Successfully--------------------");
      docRetrievalManager.release();

    } catch (UnsupportedEncodingException unsee) {
      log.error("Error when send email attachment - UnsupportedEncodingException", unsee);
      throw new ApplicationException(DmsErrorConstant.ERROR_DMS_SEND_EMAIL, unsee);
    }catch(ApplicationException appEx){
      throw appEx;
    } catch (Exception e) {
      log.error("Error when send email attachment", e);
      throw new ApplicationException(DmsErrorConstant.ERROR_DMS_SEND_EMAIL, e);
    } finally {
      try {
        dataStream.close();
      } catch (Exception exp) {
        log.error("Exception caught while closing data stream.", exp);
      }
    }
    return state;
  }


  /**
   * Deletes the document relationship by the MtmDocumentRelationship object ID
   *
   * @param ID MtmDocumentRelationship object ID
   * @throws ApplicationException
   */
  public void deleteRelationship(Integer ID) throws ApplicationException {
    MtmDocumentRelationshipDAObject docRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    docRelationshipDAO.deleteRelationshipByID(ID);
    docRelationshipDAO=null;
  }

  /**
   * Gets all the sub document(s) under a parent document with the ID of parent document provided
   *
   * @param parentID the dmsDocument object ID
   * @return List of the sub document under the parent document
   * @throws ApplicationException
   */
  public List getSubDocumentByParentID(Integer parentID) throws ApplicationException{
    DmsDocumentDAObject dmsDocumentDAO=new DmsDocumentDAObject(sessionContainer,conn);
    List allDocumentList=new ArrayList();
    allDocumentList=dmsDocumentDAO.getListByParentID(parentID,null);
    return allDocumentList;
  }

  /**
   * Gets the string array from the default profile setting which used for the options shown in select menu.
   *
   * <PRE>
   *
   * This method gets option values of the default profile field type
   * DmsDefaultProfileSetting.FIELD_TYPE_SELECT_DATABASE The return string array contains all the option value as array
   * element for user to select
   *
   * </PRE>
   *
   * @param dmsDefaultProfileSetting    Default DMS profile.
   * @return String array of option
   */
  public String[] getDefaultOptionStringArray(DmsDefaultProfileSetting dmsDefaultProfileSetting) throws ApplicationException {
    String[] result = null;

    if (DmsDefaultProfileSetting.FIELD_TYPE_SELECT_DATABASE.equals(dmsDefaultProfileSetting.getFieldType())) {
      java.sql.PreparedStatement preStat = null;
      java.sql.ResultSet rs = null;
      try {
        preStat = conn.prepareStatement(dmsDefaultProfileSetting.getSqlStat());
        preStat.setInt(1, dmsDefaultProfileSetting.getID().intValue());
        rs = preStat.executeQuery();
        List tmpList = new ArrayList();
        while (rs.next()) {
          String value = "";
          value = rs.getString(1);
          tmpList.add(value);
        }
        result = new String[tmpList.size()+1];
        result[0] = MessageResourcesFactory.getMessage(sessionContainer.getSessionLocale(), "common.options.select_menu.select_one");
        for (int i = 0; i < tmpList.size(); i++) {
          result[i+1] = (String)tmpList.get(i);
        }
      } catch (Exception e) {
        log.error("Error when get data by Profile SQL statement.", e);
        throw new ApplicationException(ErrorConstant.DB_SELECT_ERROR);
      } finally {
        try {
          rs.close();
        } catch (Exception ignore) {
        } finally {
          rs = null;
      }
        try {
          preStat.close();
        } catch (Exception ignore) {
        } finally {
          preStat = null;
    }
      }
    }

    return(result);
  }

  /**
   * Copies the compound document to a destination folder
   *
   * <Pre>
   *
   * Options: copyFileOpt - 1.DmsOperationConstant.COPY_OPERATION_AS_NEW, create a new effective start of the copied
   * document 2.DmsOperationConstant.COPY_OPERATION_AS_OLD, user the effective start and end date of the source document
   *
   *  copyVersionOpt - 1.DmsOperationConstant.COPY_ALL_VERSIONS, copy all ther version(s) of the source document.
   *                   2.DmsOperationConstant.COPY_TOP_VERSION, copy the top version of the source document only.
   *
   * bDocumentActive - 1.true, set the record status of the source document as active 2.false, set the record status of
   * the source doucment as pending
   *
   * During the copy, the update alert is updated audit trail of copy operation Update the index stored in db and lucene
   *
   *
   * </Pre>
   *
   * @param sourceDocument the source dmsDocument object
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID            the destination root ID
   * @param copyFileOpt       copy file document life cycle option
   * @param copyVersionOpt    copy versions of document option
   * @param bDocumentActive   after copy set the record status of the source document as active or pending
   * @return the copied dmsDocument object
   * @throws ApplicationException
   * @see com.dcivision.dms.DmsOperationConstant
   *
   */

  public DmsDocument copyCompoundDoc(DmsDocument sourceDocument, DmsDocument destinationFolder, Integer rootID, String copyFileOpt,
      String copyVersionOpt, boolean bDocumentActive) throws ApplicationException {
    DmsDocumentDAObject dmsDocumentDAO=new DmsDocumentDAObject(sessionContainer,conn);
    DocumentValidateManager docValidateManager=new DocumentValidateManager(sessionContainer,conn);
    docValidateManager.checkStorageLimitAvailable(sourceDocument);
    DmsDocument newDocument = (DmsDocument) dmsDocumentDAO.insertObject(sourceDocument);
    this.copyDocument(sourceDocument, destinationFolder, rootID, copyFileOpt, copyVersionOpt, bDocumentActive);
    return newDocument;
  }

  /**
   * Creates workflow paper doucment shortcut
    *
   * @param sourceDoc the source paper document
   * @throws ApplicationException
    */

  public DmsDocument createWFPaperDocShortCut(DmsDocument sourceDoc)throws ApplicationException {
    DmsDocument dmsDocument = new DmsDocument();
    dmsDocument = (DmsDocument)sourceDoc.clone();
    /* special settiing for shortcut*/
    dmsDocument.setDocumentType(DmsDocument.DOCUMENT_LINK);
    dmsDocument.setItemStatus(GlobalConstant.STATUS_INACTIVE);
    dmsDocument.setItemSize(null);
    dmsDocument = this.createDocument(dmsDocument, null, false);

    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(dmsDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_INSERT,
        DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_PARAM, null);
    this.indexLUCENE(indexCache, dmsDocument, null, null);

    MtmDocumentRelationship docRelationship = new MtmDocumentRelationship();
    docRelationship.setDocumentName(sourceDoc.getDocumentName());
    docRelationship.setRootID(sourceDoc.getRootID());
    docRelationship.setParentID(sourceDoc.getParentID());
    docRelationship.setDocumentID(sourceDoc.getID());
    docRelationship.setRelatedDocumentID(dmsDocument.getID());
    docRelationship.setRelationshipType(DmsDocument.DOCUMENT_LINK);

    docRelationship = this.createDocumentRelationship(docRelationship, dmsDocument);
    return dmsDocument;

  }

  /**
  * Send multi document as attachment in an email
    *
  * @param sender temporary no use
  * @param email the DmsSendEmail object
  * @param documentID the series of document id desplit with "," e.g 1001,1002,1003 for 3 document id
  * @param version the version ID or Top version to get the physical file as attachment.
  * @return status DmsOperationConstant.EMAIL_SENT if send successfully
    */
  public String sendMultiDocumentByEmailAttachement(String sender, DmsSendEmail email, String documentID, String version)
      throws ApplicationException {
    String state = "";
    InputStream dataStream=null;
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    String []documentIDArray=TextUtility.splitString(documentID,",");
    DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);

    try {
      // create an email
      EmailDeliveryMessage msg = new EmailDeliveryMessage();

      String curUserEmail = UserInfoFactory.getUserEmailAddress(sessionContainer.getUserRecordID());
      if (Utility.isEmpty(curUserEmail)) {
        curUserEmail = SystemParameterFactory.getSystemParameter(SystemParameterConstant.SMTP_ADMIN_ADDRESS);
      }
      String curUserName = UserInfoFactory.getUserFullName(sessionContainer.getUserRecordID());
      if (Utility.isEmpty(curUserName)) {
        curUserName = SystemParameterFactory.getSystemParameter(SystemParameterConstant.SMTP_ADMIN_NAME);
      }
      msg.setSender(new GenericAddress(curUserEmail, curUserName,"utf-8"));


      String[] toRecipients = TextUtility.splitString(email.getRecipients(), ";");
      for (int i = 0; i < toRecipients.length; ++i) {
        msg.addToRecipient(new GenericAddress(toRecipients[i]));
      }
      if (!Utility.isEmpty(email.getCCRecipients())) {
        String[] ccRecipients = TextUtility.splitString(email.getCCRecipients(), ";");
        for (int i = 0; i < ccRecipients.length; ++i) {
          msg.addCCRecipient(new GenericAddress(ccRecipients[i]));
        }
      }
      if (!Utility.isEmpty(email.getBCCRecipients())) {
        String[] bccRecipients = TextUtility.splitString(email.getBCCRecipients(), ";");
        for (int i = 0; i < bccRecipients.length; ++i) {
          msg.addBCCRecipient(new GenericAddress(bccRecipients[i]));
        }
      }
      msg.setCharset(SystemParameterFactory.getSystemParameter(SystemParameterConstant.ENCODING));
      msg.setSubject(email.getSubject());
      msg.setMailContent(email.getContent());

      // add attachment
      for(int i=0;i<documentIDArray.length;i++){
      DmsDocument document = docRetrievalManager.getDocument(TextUtility.parseIntegerObj(documentIDArray[i]));
      Integer versionID = new Integer(1);
      DmsVersion dmsVersion = new DmsVersion();
      Integer contentID = new Integer(0);
      if (!Utility.isEmpty(version) && !DmsOperationConstant.DMS_TOP_VERSION.equals(version)) {
        versionID = TextUtility.parseIntegerObj(version);
        dmsVersion = docRetrievalManager.getVersionByVersionID(versionID);
        contentID = dmsVersion.getContentID();
        } else {
        dmsVersion = docRetrievalManager.getTopVersionByDocumentID(TextUtility.parseIntegerObj(documentIDArray[i]));
        contentID = dmsVersion.getContentID();
      }

      /* Check for document link attachement */
      if (DmsDocument.DOCUMENT_LINK.equals(document.getDocumentType())) {
        MtmDocumentRelationshipDAObject docRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
        Integer targetDocID = docRelationshipDAO.getTargetDocIDByRelatedDocID(document.getID(), document.getDocumentType());
        DmsDocument targetDoc = docRetrievalManager.getDocument(targetDocID);
        /* Used to update the doc link name and type; Wont infulence the getDocumentProfileInfo() */
        targetDoc.setDocumentName(document.getDocumentName());
        targetDoc.setDocumentType(document.getDocumentType());
        //update the doc ID for shortcut linkage
        document = targetDoc;

        //update the real link document version
        dmsVersion = docRetrievalManager.getTopVersionByDocumentID(targetDocID);
        contentID = dmsVersion.getContentID();
        docRelationshipDAO=null;
      }
      /*End the Document link attachement handling */

      DmsContent docContent = docRetrievalManager.getContentByContentID(contentID);

      dataStream  = dmsContentManager.readDmsDocumentStoreContent(document,docContent);
      String contentType = URLConnection.guessContentTypeFromName(document.getDocumentName());
      if (contentType == null) {
        contentType = "application/octect-stream";
      }

      msg.addAttachment(document.getDocumentName(), dataStream);
      msg.setContentType(contentType);
      }
      // send email
      NotificationWay emailNotification = NotificationWayFactory.getNotificationInstance(NotificationWay.EMAIL_NOTIFICATION_INSTANCE);
      emailNotification.addDeliveryMessage( msg);
      emailNotification.send();
      state=DmsOperationConstant.EMAIL_SENT;
      log.debug("---------------Message Send Successfully--------------------");
      docRetrievalManager.release();

    } catch (UnsupportedEncodingException unsee) {
      log.error("Error when send email attachment - UnsupportedEncodingException", unsee);
      throw new ApplicationException(DmsErrorConstant.ERROR_DMS_SEND_EMAIL, unsee);
    } catch (Exception e) {
      log.error("Error when send email attachment", e);
      throw new ApplicationException(DmsErrorConstant.ERROR_DMS_SEND_EMAIL, e);
    } finally {
      try {
        dataStream.close();
      } catch (Exception ignore) {
      } finally {
        conn = null;
    }
    }
    return state;
  }


  /**
   * Copy the physical file in DMS to other Location Master, if the move/copy destination is not the same location
   * master with the source document.
   *
   * <P>
   * For move operations, after copy the physical file to the destination, the source physical files will be deleted.
   * </P>
   *
   *
   * @param dmsDocument the dmsDocument object to be copied or moved
   * @param sourceLoc the location master of the source document
   * @param destinationLoc the location master of the destination folder
   * @param mode
   *
   * <pre>
   *   to determine the operation is copy or move operation, if move operation the mode will
   *   DmsOperationConstant.MOVE_OPERATION, if copy operation DmsOperationConstant.COPY_OPERATION
   * </pre>
   *
   * @param copyVersionOpt
   *
   * <pre>
   *   copyVersionOpt - 1.DmsOperationConstant.COPY_ALL_VERSIONS, copy all ther version(s) of source physical files.
   *                    2.DmsOperationConstant.COPY_TOP_VERSION, copy the top version of the source physical files.
   *
   * </pre>
   *
   * @throws ApplicationException
   *
   *  <pre>
   *   ApplicationException with the following message codes will be thrown
   *   DmsErrorConstant.PHYSICAL_FILE_NOT_FOUND - No physcial file error
   *  </pre>
   */
  private void moveCopyPhysicalDocument(DmsDocument dmsDocument, DmsLocMaster sourceLoc, DmsLocMaster destinationLoc, String mode,
      String copyVersionOpt) throws ApplicationException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DmsVersionDAObject versionDAO = new DmsVersionDAObject(sessionContainer, conn);
    List versionList = new ArrayList();
    List deleteContentList = new ArrayList();
    DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);

    // get all the version of document (this implementation only valid for
    // linear version)
    versionList = versionDAO.getParentVersionsListByParentIDByDocumentID(null, dmsDocument.getID());

    if ((DmsOperationConstant.COPY_ALL_VERSIONS.equals(copyVersionOpt)) || (DmsOperationConstant.MOVE_OPERATION.equals(mode))) {

      versionList = versionDAO.getParentVersionsListByParentIDByDocumentID(null, dmsDocument.getID());
    } else {
      DmsVersion topVersion = (DmsVersion) versionDAO.getTopVersionByDocumentID(dmsDocument.getID());
      topVersion.setVersionNumber("1");
      topVersion.setParentID(new Integer(0));
      topVersion.setVersionLabel(DmsOperationConstant.DMS_ROOT);
      versionList.add(topVersion);
    }
    DmsContentDAObject contentDAO = new DmsContentDAObject(sessionContainer, conn);


    for (int i = versionList.size() - 1; i >= 0; i--) {
      DmsVersion version = (DmsVersion) versionList.get(i);
      // get all content link of version
      DmsContent content = (DmsContent) contentDAO.getObjectByID(version.getContentID());

      String converted = content.getConvertedName() == null ? "" : content.getConvertedName();
      try {
        if (!DmsDocument.PAPER_DOC_TYPE.equals(dmsDocument.getDocumentType())) {
          // read source file
          InputStream dataStream = dmsContentManager.readDmsDocumentStoreContent(dmsDocument, content);
          // write to destinationLoc
          dmsContentManager.writeDmsDocumentStoreContent(dmsDocument, destinationLoc, converted, dataStream);
        }
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(DmsErrorConstant.PHYSICAL_FILE_NOT_FOUND, e);
      }

      if (DmsOperationConstant.MOVE_OPERATION.equals(mode)) {
        deleteContentList.add(content);
      }
    }

    // move operation delete all the source physical files
    if (DmsOperationConstant.MOVE_OPERATION.equals(mode)) {
      for (int i = deleteContentList.size() - 1; i >= 0; i--) {
        DmsContent content = (DmsContent) deleteContentList.get(i);
        try {
          if (!DmsDocument.PAPER_DOC_TYPE.equals(dmsDocument.getDocumentType())) {
            // delete source file
            dmsContentManager.deleteDmsDocumentStoreContent(dmsDocument, content);
          }
        } catch (Exception e) {
          log.error(e, e);
          throw new ApplicationException(DmsErrorConstant.PHYSICAL_FILE_NOT_FOUND, e);
        }
      }
    }

    docRetrievalManager.release();
  }


  /**
   * Copies the specified version document to a destination folder
   *
   * <Pre>
   *
   * Options: copyFileOpt - 1.DmsOperationConstant.COPY_OPERATION_AS_NEW, create a new effective start of the copied
   * document 2.DmsOperationConstant.COPY_OPERATION_AS_OLD, user the effective start and end date of the source document
   *
   * bDocumentActive - 1.true, set the record status of the source document as active 2.false, set the record status of
   * the source doucment as pending
   *
   * During the copy, the update alert is updated audit trail of copy operation Update the index stored in db and lucene
   *
   *
   * </Pre>
   *
   * @param destinationFolder the destination folder dmsDocument object
   * @param rootID the destination root ID
   * @param copyFileOpt copy file document life cycle option
   * @param versionID the specified version to be copied
   * @param bDocumentActive after copy set the record status of the source document as active or pending
   * @return the copied dmsDocument object
   * @throws UnsupportedOperationException
   * @throws ApplicationException
   * @see com.dcivision.dms.DmsOperationConstant
   *
   */
  public void copyDocumentByVersionID(DmsDocument destinationFolder, Integer rootID, String copyFileOpt, Integer versionID,
      boolean bDocumentActive) throws UnsupportedOperationException, ApplicationException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
    MtmDocumentVersionDAObject mtmDocumentVersionDAObject = new MtmDocumentVersionDAObject(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);

    DmsDocument sourceDocument = (DmsDocument)mtmDocumentVersionDAObject.getDocumentByVersionID(versionID);
    DmsDocument originalDocument = (DmsDocument)sourceDocument.clone();
    DmsDocument newDocument = new DmsDocument();

    // get all the version of document (this implementation only valid for linear version)
    DmsVersionDAObject versionDAO = new DmsVersionDAObject(sessionContainer, conn);
    List versionList = new ArrayList();

    DmsVersion topVersion = (DmsVersion) versionDAO.getObjectByID(versionID);
    if(sourceDocument.getDocumentName().indexOf(".") > 0 ){
        String documentNameTemp = sourceDocument.getDocumentName();
        int postfixLocation = documentNameTemp.lastIndexOf(".");
        String postfix = documentNameTemp.substring(postfixLocation,documentNameTemp.length());
        String fileName = documentNameTemp.substring(0,postfixLocation);
        sourceDocument.setDocumentName(fileName+"_"+topVersion.getVersionLabel()+postfix);
    }
    sourceDocument.setReferenceNo(topVersion.getReferenceNo());
    sourceDocument.setDescription(topVersion.getDescription());

    topVersion.setVersionNumber("1");
    topVersion.setParentID(new Integer(0));
    topVersion.setVersionLabel(DmsOperationConstant.DMS_ROOT);
    versionList.add(topVersion);

    if(!DmsDocument.COMPOUND_DOC_TYPE.equals(sourceDocument.getDocumentType())){
      sourceDocument.setRootID(destinationFolder.getRootID());
      sourceDocument.setParentID(destinationFolder.getID());

      //Check for available space
      docValidateManager.checkStorageLimitAvailable(sourceDocument);
      log.debug("Available space exists for current document");

      // create document

      if (DmsOperationConstant.COPY_OPERATION_AS_NEW.equals(copyFileOpt)) {
        sourceDocument.setEffectiveStartDate(new Timestamp(System.currentTimeMillis()));
        sourceDocument.setEffectiveEndDate(null);
      }
      sourceDocument.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
      sourceDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);
      sourceDocument.setOwnerID(sessionContainer.getUserRecordID());

      if (bDocumentActive) {
        sourceDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
      } else {
        sourceDocument.setRecordStatus(GlobalConstant.RECORD_PENDING);
      }
      newDocument = (DmsDocument) dmsDocumentDAO.insertObject(sourceDocument);
    }else{
      newDocument=dmsDocumentDAO.getDocumentByNameParentID(sourceDocument.getDocumentName(),destinationFolder.getID());
    }

    log.debug("related version list = " + versionList.size());
    log.debug("destination Folder name = " +destinationFolder.getDocumentName());

    DmsContentDAObject contentDAO = new DmsContentDAObject(sessionContainer, conn);
    DmsContent newContent = new DmsContent();
    //DmsVersion newVersion = new DmsVersion();
    Boolean supportPhysicalCopy = new Boolean(SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.DMS_SUPPORT_PHYSICAL_FILE_COPY));

    //NOTE: link to physical content can be a abstract link which allow copy operation do not
    // involve copy a content to a separate entity by linking to the content concurrently.
    if (supportPhysicalCopy.booleanValue()) {
      //TODO: Get the original content and create a new physical file
    }else{
      for (int i = versionList.size()-1; i >= 0; i--) {
        DmsVersion version = (DmsVersion) versionList.get(i);
        // get all content link of version
        DmsContent content = (DmsContent) contentDAO.getObjectByID(version.getContentID());
        newContent.setID(null);
        newContent = (DmsContent) contentDAO.insertObject(content);
        version.setDocumentID(newDocument.getID());
        version.setContentID(newContent.getID());
        versionDAO.insertObject(version);
      }
    }

    //copy document details if any
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    List docDetailList = docDetailDAO.getListByDocumentID(sourceDocument.getID());
    List newDocDetailList = new ArrayList();
    if (docDetailList != null){
      for(int i=0 ; i<docDetailList.size(); i++){
        DmsDocumentDetail docDetail = (DmsDocumentDetail) docDetailList.get(i);
        docDetail.setDocumentID(newDocument.getID());
        docDetail = (DmsDocumentDetail)docDetailDAO.insertObject(docDetail);
        newDocDetailList.add(docDetail);
        if (i==0) {
          newDocument.setUserDefinedFieldID(docDetail.getUserDefinedFieldID());
        }
      }
    }

    log.debug("created doc detail ");
    newDocument.setDocumentDetails(newDocDetailList);
    //end of copy document details

    /* Check for Document Relationship type */
    MtmDocumentRelationshipDAObject mtmRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    MtmDocumentRelationship mtmRelationship = (MtmDocumentRelationship) mtmRelationshipDAO.getObjectByRelatedDocID(sourceDocument.getID(),
        null);

    if (mtmRelationship!=null){
      mtmRelationship.setRelatedDocumentID(newDocument.getID());
      mtmRelationshipDAO.insertObject(mtmRelationship);
    }



    //if difference dms root location master copy the physical document
    RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);
    if(originalDocument.getRootID().intValue()!=destinationFolder.getRootID().intValue()){
      DmsLocMaster sourceRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(originalDocument);
      DmsLocMaster destinationRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(destinationFolder);

      if(sourceRootLoc.getID().intValue()!= destinationRootLoc.getID().intValue()){
        if(!sourceRootLoc.getLocPath().equals(destinationRootLoc.getLocPath())){
           //move the physical document
          moveCopyPhysicalDocument(originalDocument, sourceRootLoc, destinationRootLoc, DmsOperationConstant.COPY_OPERATION,
              DmsOperationConstant.COPY_TOP_VERSION);
        }
      }
    }


    // Full text Insert
    /*
     * if (!DmsDocument.DOCUMENT_LINK.equals(newDocument.getDocumentType()) &&
     * !DmsDocument.PAPER_DOC_TYPE.equals(newDocument.getDocumentType())) {
     *
     * //InputStream data = (InputStream)docRetrievalManager.getDataInputStreamByDocument(newDocument, newVersion,
     * newContent);
     *
     * //if(data==null ){ //try to get from source document lucene index IndexManager idxHandler =
     * FullTextIndexFactory.getInstance(); InputStream data = idxHandler.getFullText(sourceDocument.getID());
     * newDocument.setScanDocumentForFullText(true); if(data == null){ data =
     * (InputStream)docRetrievalManager.getDataInputStreamByDocument(newDocument, newVersion, newContent);
     * newDocument.setScanDocumentForFullText(false); }
     *
     * //assume it is act like the scan document for indexing in lucene fulltext
     *
     * //} indexDocument(newDocument, data, GlobalConstant.OP_MODE_INSERT); }
    */
    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_INSERT,
        DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_PARAM, null);
    this.indexLUCENE(indexCache, newDocument, newContent, null);


    // Alert copy document
    try {
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      am.call(UpdateAlert.DOCUMENT_TYPE, destinationFolder.getID(), UpdateAlert.CREATE_ACTION, sourceDocument.getDocumentName(), null,
          null, null, newDocument.getID());
      am.release();
    } catch (Exception e) {
      log.error("Error when doing alert", e);

    }

    // Log down in audit trail
    if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDocument.getDocumentType()))) {// barbin
                                                                                                                                  // EIP-1296
      AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, sourceDocument, AuditTrailConstant.ACCESS_TYPE_COPY, null);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDocument, AuditTrailConstant.ACCESS_TYPE_COPY_CREATE, null);
      auditManager.release();
    }

    dmsDocumentDAO=null;
    versionDAO = null;
    contentDAO=null;
    docDetailDAO=null;
    mtmRelationshipDAO=null;
    docRetrievalManager.release();
    docValidateManager.release();
  }

  //add by dick
  //for workflow
  public void copyDocumentByVersionIDForWF(DmsDocument destinationFolder, Integer rootID, String copyFileOpt, Integer versionID,
      boolean bDocumentActive) throws UnsupportedOperationException, ApplicationException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DocumentValidateManager docValidateManager = new DocumentValidateManager(sessionContainer, conn);
    MtmDocumentVersionDAObject mtmDocumentVersionDAObject = new MtmDocumentVersionDAObject(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);

    DmsDocument sourceDocument = (DmsDocument)mtmDocumentVersionDAObject.getDocumentByVersionID(versionID);
    DmsDocument originalDocument = (DmsDocument)sourceDocument.clone();
    DmsDocument newDocument = new DmsDocument();

    // get all the version of document (this implementation only valid for linear version)
    DmsVersionDAObject versionDAO = new DmsVersionDAObject(sessionContainer, conn);
    List versionList = new ArrayList();
/*
     * if(DmsOperationConstant.COPY_ALL_VERSIONS.equals(copyVersionOpt)){ versionList =
     * versionDAO.getParentVersionsListByParentIDByDocumentID(null, sourceDocument.getID()); }else
     * if(DmsOperationConstant.COPY_TOP_VERSION.equals(copyVersionOpt)){ DmsVersion topVersion = (DmsVersion)
     * versionDAO.getTopVersionByDocumentID(sourceDocument.getID()); topVersion.setVersionNumber("1");
     * topVersion.setParentID(new Integer(0)); topVersion.setVersionLabel(DmsOperationConstant.DMS_ROOT);
     * versionList.add(topVersion); }else{// copy the specify verson document
*/
    DmsVersion topVersion = (DmsVersion) versionDAO.getObjectByID(versionID);
    if(sourceDocument.getDocumentName().indexOf(".") > 0 ){
        String documentNameTemp = sourceDocument.getDocumentName();
        int postfixLocation = documentNameTemp.lastIndexOf(".");
        String postfix = documentNameTemp.substring(postfixLocation,documentNameTemp.length());
        String fileName = documentNameTemp.substring(0,postfixLocation);
        sourceDocument.setDocumentName(fileName+"_"+topVersion.getVersionLabel()+ "_" + versionID.toString() +postfix);
    }
    sourceDocument.setReferenceNo(topVersion.getReferenceNo());
    sourceDocument.setDescription(topVersion.getDescription());

    topVersion.setVersionNumber("1");
    topVersion.setParentID(new Integer(0));
    topVersion.setVersionLabel(DmsOperationConstant.DMS_ROOT);
    versionList.add(topVersion);

//    }


    if(!DmsDocument.COMPOUND_DOC_TYPE.equals(sourceDocument.getDocumentType())){
      sourceDocument.setRootID(destinationFolder.getRootID());
      sourceDocument.setParentID(destinationFolder.getID());

      //Check for available space
      docValidateManager.checkStorageLimitAvailable(sourceDocument);
      log.debug("Available space exists for current document");

      // create document

      if (DmsOperationConstant.COPY_OPERATION_AS_NEW.equals(copyFileOpt)) {
        sourceDocument.setEffectiveStartDate(new Timestamp(System.currentTimeMillis()));
        sourceDocument.setEffectiveEndDate(null);
      }
      sourceDocument.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
      sourceDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);
      sourceDocument.setOwnerID(sessionContainer.getUserRecordID());

      if (bDocumentActive) {
        sourceDocument.setRecordStatus(GlobalConstant.RECORD_STATUS_ACTIVE);
      } else {
        sourceDocument.setRecordStatus(GlobalConstant.RECORD_PENDING);
      }
      newDocument = (DmsDocument) dmsDocumentDAO.insertObject(sourceDocument);
    }else{
      newDocument=dmsDocumentDAO.getDocumentByNameParentID(sourceDocument.getDocumentName(),destinationFolder.getID());
    }

    log.debug("related version list = " + versionList.size());
    log.debug("destination Folder name = " +destinationFolder.getDocumentName());

    DmsContentDAObject contentDAO = new DmsContentDAObject(sessionContainer, conn);
    DmsContent newContent = new DmsContent();
    DmsVersion newVersion = new DmsVersion();
    Boolean supportPhysicalCopy = new Boolean(SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.DMS_SUPPORT_PHYSICAL_FILE_COPY));

    //NOTE: link to physical content can be a abstract link which allow copy operation do not
    // involve copy a content to a separate entity by linking to the content concurrently.
    if (supportPhysicalCopy.booleanValue()) {
      //TODO: Get the original content and create a new physical file
    }else{
      for (int i = versionList.size()-1; i >= 0; i--) {
        DmsVersion version = (DmsVersion) versionList.get(i);
        // get all content link of version
        DmsContent content = (DmsContent) contentDAO.getObjectByID(version.getContentID());
        content.setID(null);
        newContent = (DmsContent) contentDAO.insertObject(content);
        version.setDocumentID(newDocument.getID());
        version.setContentID(newContent.getID());
        newVersion = (DmsVersion) versionDAO.insertObject(version);
        createDocumentVersionRelationship(newDocument, newVersion);
      }
    }

    //copy document details if any
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    List docDetailList = docDetailDAO.getListByDocumentID(sourceDocument.getID());
    List newDocDetailList = new ArrayList();
    if (docDetailList != null){
      for(int i=0 ; i<docDetailList.size(); i++){
        DmsDocumentDetail docDetail = (DmsDocumentDetail) docDetailList.get(i);
        docDetail.setDocumentID(newDocument.getID());
        docDetail = (DmsDocumentDetail)docDetailDAO.insertObject(docDetail);
        newDocDetailList.add(docDetail);
        if (i==0) {
          newDocument.setUserDefinedFieldID(docDetail.getUserDefinedFieldID());
        }
      }
    }

    log.debug("created doc detail ");
    newDocument.setDocumentDetails(newDocDetailList);
    //end of copy document details

    /* Check for Document Relationship type */
    MtmDocumentRelationshipDAObject mtmRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    MtmDocumentRelationship mtmRelationship = (MtmDocumentRelationship) mtmRelationshipDAO.getObjectByRelatedDocID(sourceDocument.getID(),
        null);

    if (mtmRelationship!=null){
      mtmRelationship.setRelatedDocumentID(newDocument.getID());
      mtmRelationshipDAO.insertObject(mtmRelationship);
    }



    //if difference dms root location master copy the physical document
    RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);
    if(originalDocument.getRootID().intValue()!=destinationFolder.getRootID().intValue()){
      DmsLocMaster sourceRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(originalDocument);
      DmsLocMaster destinationRootLoc = rootRetrievalManager.getTargetLocMasterByDocument(destinationFolder);

      if(sourceRootLoc.getID().intValue()!= destinationRootLoc.getID().intValue()){
        if(!sourceRootLoc.getLocPath().equals(destinationRootLoc.getLocPath())){
           //move the physical document
          moveCopyPhysicalDocument(originalDocument, sourceRootLoc, destinationRootLoc, DmsOperationConstant.COPY_OPERATION,
              DmsOperationConstant.COPY_TOP_VERSION);
        }
      }
    }


    // Full text Insert
    /*
     * if (!DmsDocument.DOCUMENT_LINK.equals(newDocument.getDocumentType()) &&
     * !DmsDocument.PAPER_DOC_TYPE.equals(newDocument.getDocumentType())) {
     *
     * //InputStream data = (InputStream)docRetrievalManager.getDataInputStreamByDocument(newDocument, newVersion,
     * newContent);
     *
     * //if(data==null ){ //try to get from source document lucene index IndexManager idxHandler =
     * FullTextIndexFactory.getInstance(); InputStream data = idxHandler.getFullText(sourceDocument.getID());
     * newDocument.setScanDocumentForFullText(true); if(data == null){ data =
     * (InputStream)docRetrievalManager.getDataInputStreamByDocument(newDocument, newVersion, newContent);
     * newDocument.setScanDocumentForFullText(false); }
     *
     * //assume it is act like the scan document for indexing in lucene fulltext
     *
     * //} indexDocument(newDocument, data, GlobalConstant.OP_MODE_INSERT); }
    */
    DmsDocumentIndexCache indexCache = new DmsDocumentIndexCache(newDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_INSERT,
        DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_PARAM, null);
    this.indexLUCENE(indexCache, newDocument, newContent, null);

    // Alert copy document
    try {
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      am.call(UpdateAlert.DOCUMENT_TYPE, destinationFolder.getID(), UpdateAlert.CREATE_ACTION, sourceDocument.getDocumentName(), null,
          null, null, newDocument.getID());
      am.release();
    } catch (Exception e) {
      log.error("Error when doing alert", e);

    }

    // Log down in audit trail
    if (sessionContainer.getUserRecordID() != null && (!DmsDocument.TIF_ANNOTATION_TYPE.equals(newDocument.getDocumentType()))) {// barbin
                                                                                                                                  // EIP-1296
      AuditTrailManager auditManager = new AuditTrailManager(sessionContainer, conn);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, sourceDocument, AuditTrailConstant.ACCESS_TYPE_COPY, null);
      auditManager.auditTrail(GlobalConstant.OBJECT_TYPE_DOCUMENT, newDocument, AuditTrailConstant.ACCESS_TYPE_COPY_CREATE, null);
      auditManager.release();
    }

    dmsDocumentDAO=null;
    versionDAO = null;
    contentDAO=null;
    docDetailDAO=null;
    mtmRelationshipDAO=null;
    docRetrievalManager.release();
    docValidateManager.release();
  }




  /**
   * Deletes the folder with sub document(s)/ folder(s) The folder is not allow to deletes if its sub document(s) or
   * folder(s) that have been checkout and no permssion. And also the sub document(s) is checked out or the sub
   * document(s)/ folder(s) no permission to delete, then that sub document(s) will not be deleted.
   *
   * @param folder the folder dmsDocument object to be deleted
   * @return List of document(s) that check for delete operation
   *
   * <pre>
   *   the element of the return list contains a list with 2 element,
   *    first element:  check delete allow or not dmsDocument object
   *    second element: status of delete
   *                    P - No permission to delete the document , not allow to delete
   *                    C - the check delete allow or not dmsDocument object is checkout, not allow to delete
   *                    S- the document that delete success, allow to delete
   * </pre>
   *
   * @throws ApplicationException
   * @throws SubElementContainedException
   */
  public List deleteFolderExpectSpecDocument(DmsDocument folder) throws ApplicationException, SubElementContainedException {
    Integer folderID = folder.getID();
    String folderName = folder.getDocumentName();
    List returnMessageList = new ArrayList();
    // check whether there is document within the folder
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    PermissionManager permManager = sessionContainer.getPermissionManager();

    List documentList = dmsDocumentDAO.getListByParentID(folder.getID(), folder.getRootID(),"*", true);

    //if this folder not allow delete ,return immediacy
    if(!permManager.hasAccessRight(conn,"D",folder.getID(), "D")){
        List tempList = new ArrayList();
        tempList.add(folder);
        tempList.add(new String("P") );
        returnMessageList.add(tempList);
        return returnMessageList;
    }

    DmsDocument childDocument = new DmsDocument();
    boolean hasNotAllowDocument = false;
    //delete children
    for (int i=0; i < documentList.size(); i++){
      childDocument = (DmsDocument) documentList.get(i);
      if (DmsDocument.FOLDER_TYPE.equals(childDocument.getDocumentType())
          || DmsDocument.COMPOUND_DOC_TYPE.equals(childDocument.getDocumentType())
          || DmsDocument.PAPER_DOC_TYPE.equals(childDocument.getDocumentType())) {
        if(permManager.hasAccessRight(conn,"D",childDocument.getID(), "D")){
            List tmpNotDeleteDocumentList = new ArrayList();
            tmpNotDeleteDocumentList = deleteFolderExpectSpecDocument(childDocument);
            if (!Utility.isEmpty(tmpNotDeleteDocumentList)) {
                returnMessageList.addAll(tmpNotDeleteDocumentList);
                //hasNotAllowDocument = true;
                if(!Utility.isEmpty(tmpNotDeleteDocumentList)){
                  for(int j = 0 ; j < tmpNotDeleteDocumentList.size() ;j++){
                    List tempList = (List)tmpNotDeleteDocumentList.get(j);
                //DmsDocument tmpDocument = (DmsDocument) tempList.get(0);
                    String tempDeleteType =  (String)tempList.get(1);
                    if("C".equals( tempDeleteType)){
                      hasNotAllowDocument = true;
                      break;
                    }
                    if("P".equals( tempDeleteType)){
                      hasNotAllowDocument = true;
                      break;
                    }
                  }
                }

            }
        }else{
            //'cas not permission not delete file
            List tempList = new ArrayList();
            tempList.add(childDocument);
            tempList.add(new String("P") );
            returnMessageList.add(tempList);
            hasNotAllowDocument = true;
        }
      } else {
        // checkouted and not permission document not allow delete
        if(!permManager.hasAccessRight(conn,"D",childDocument.getID(), "D")){
            //'cas not delete permission  not allow delete file
            List tempList = new ArrayList();
            tempList.add(childDocument);
            tempList.add(new String("P") );
            returnMessageList.add(tempList);
            hasNotAllowDocument = true;
        }else if (DmsVersion.EXCLUSIVE_LOCK.equals(childDocument.getItemStatus())) {
            //'cas checkouted not delete file
            List tempList = new ArrayList();
            tempList.add(childDocument);
            tempList.add(new String("C") );
            returnMessageList.add(tempList);
            hasNotAllowDocument = true;
        }else{
            List tempList = new ArrayList();
            tempList.add(childDocument);
            tempList.add(new String("S") );
            returnMessageList.add(tempList);
            deleteDocument(childDocument);
        }
      }
    }

    //finally, delete the folder
    //have checkout document ,not allow delete
    if(hasNotAllowDocument == false){
        List tempList = new ArrayList();
        tempList.add(folder);
        tempList.add(new String("S") );
        returnMessageList.add(tempList);
        deleteDocument(folder);
    }


    //delete folder; check for alert notification
    try {
      AdapterMaster am = new AdapterMaster(sessionContainer, conn);
      am.call(UpdateAlert.DOCUMENT_TYPE, folderID, UpdateAlert.DELETE_ACTION, folderName, null, null, null, folder.getID() );
      am.release();
    } catch (Exception e) {
      log.error("Error when doing alert", e);
    }

    dmsDocumentDAO=null;

    return returnMessageList;
  }

  /**
   * this function is to deal with update alert. This method is handle the update alert when the move operation carry
   * out.
   *
   * @param updateAlert the UpdateAlert object
   * @param actionType the action type
   * @throws ApplicationException
   */
  protected void dealUpdateAlert(UpdateAlert updateAlert,String actionType) throws ApplicationException{
        UpdateAlertTypeDAObject updateAlertTypeDAO = new UpdateAlertTypeDAObject(sessionContainer, conn);
    MtmUpdateAlertRecipientDAObject mtmUpdateAlertRecipientDAO=new MtmUpdateAlertRecipientDAObject(sessionContainer,conn);
    AlertManager alertManager = new AlertManager(sessionContainer, conn);
    UpdateAlertSystemLogDAObject alertSystemDAO = new UpdateAlertSystemLogDAObject(sessionContainer, conn);
    List updateAlertTypeAry = updateAlertTypeDAO.getByUpdateAlertIDByOwnerID(updateAlert.getID(), actionType, null);
    for(int i=0;i<updateAlertTypeAry.size();i++){
      UpdateAlertType updateAlertType=(UpdateAlertType)updateAlertTypeAry.get(i);
      List updateAlertTypeList = updateAlertTypeDAO.getByUpdateAlertIDByOwnerID(updateAlert.getID(), UpdateAlert.MOVE_ACTION,
          updateAlertType.getCreatorID());
      if(updateAlertTypeList.size()<=0){
        updateAlertType.setActionType(UpdateAlert.MOVE_ACTION);
        //updateAlertType.setCreatorID(sessionContainer.getUserRecordID());
        //updateAlertType.setu(updateAlert.getUpdaterID());
        updateAlertType=(UpdateAlertType)updateAlertTypeDAO.insertObject(updateAlertType);
        MtmUpdateAlertRecipient mtmUpdateAlertRecipient = new MtmUpdateAlertRecipient();
        mtmUpdateAlertRecipient.setUpdateAlertID(updateAlert.getID());
        mtmUpdateAlertRecipient.setUpdateAlertTypeID(updateAlertType.getID());
        mtmUpdateAlertRecipient.setRecipientType("U");
        mtmUpdateAlertRecipient.setRecipientID(updateAlertType.getCreatorID());
        mtmUpdateAlertRecipient=(MtmUpdateAlertRecipient)mtmUpdateAlertRecipientDAO.insertObject(mtmUpdateAlertRecipient);
      }else{
        UpdateAlertSystemLog alertSystemLog=alertManager.getOldAlertSystemLog(updateAlertTypeList,UpdateAlert.MOVE_ACTION);
        if(!Utility.isEmpty(alertSystemLog)){
          alertSystemLog=(UpdateAlertSystemLog)alertSystemDAO.deleteObject(alertSystemLog);
        }
      }
    }
  }

  protected boolean checkSameUserSetAlert(UpdateAlert updateAlert, String actionType, UpdateAlert oldUpdateAlert, String oldActionType)
      throws ApplicationException {
        UpdateAlertTypeDAObject updateAlertTypeDAO = new UpdateAlertTypeDAObject(sessionContainer, conn);
        if(!Utility.isEmpty(oldUpdateAlert)){
          List updateAlertTypeAry = updateAlertTypeDAO.getByUpdateAlertIDByOwnerID(updateAlert.getID(), actionType, null);
          List oldUpdateAlertTypeAry = updateAlertTypeDAO.getByUpdateAlertIDByOwnerID(oldUpdateAlert.getID(), oldActionType, null);
          for(int i=0;i<updateAlertTypeAry.size();i++){
            UpdateAlertType updateAlertType=(UpdateAlertType)updateAlertTypeAry.get(i);
            for(int j=0;j<oldUpdateAlertTypeAry.size();j++){
                  UpdateAlertType oldUpdateAlertType=(UpdateAlertType)oldUpdateAlertTypeAry.get(j);
                  if(updateAlertType.getCreatorID().equals(oldUpdateAlertType.getCreatorID())){
                    return true;
                  }
            }
          }
        }
        return false;
  }

  /**
  * Gets a list workflow record(s) that the document binded with.
  *
  * @param workflowTypeStr  the workflow category ID string
  * @param objectTypeCode   the Object type, "D" for DmsDocument
  * @param objectIdStr      the object ID, dmsDocument object ID
  * @return
   * @throws ApplicationException
   */
  public List getDmsRecordBindWorkflowList(String workflowTypeStr,String objectTypeCode,String objectIdStr) throws ApplicationException{
    //**** Check submittable workflow part START
    com.dcivision.workflow.dao.WorkflowRecordDAObject workflowRecordDAO = new com.dcivision.workflow.dao.WorkflowRecordDAObject(
        sessionContainer, conn);
    com.dcivision.workflow.dao.MtmWorkflowRecordObjectLinkDAObject workflowRecordObjectLinkDAO = new com.dcivision.workflow.dao.MtmWorkflowRecordObjectLinkDAObject(
        sessionContainer, conn);
    //String actionMode = (String)request.getAttribute(GlobalConstant.ACTION_MODE);
//    String formName = "listDmsClipboardForm";
//    boolean editFlag = false;

    Integer workflowCategoryID = TextUtility.parseIntegerObj(workflowTypeStr);
    //List profileWorkflowRecordList = workflowRecordDAO.getListCanSubmit(workflowCategoryID);
    List workflowRecordList = workflowRecordDAO.getListCanSubmit(workflowCategoryID);
    List mtmWorkflowRecordObjectLinkList = new ArrayList();
    mtmWorkflowRecordObjectLinkList = workflowRecordObjectLinkDAO.getListByObjectTypeObjectID(objectTypeCode, TextUtility
        .parseIntegerObj(objectIdStr));

    for (int i = 0; i < workflowRecordList.size(); i++) {
      boolean foundFlag = false;
      for (int j = 0; j < mtmWorkflowRecordObjectLinkList.size(); j++) {
        if (((com.dcivision.workflow.bean.WorkflowRecord) workflowRecordList.get(i)).getID().equals(
            ((com.dcivision.workflow.bean.MtmWorkflowRecordObjectLink) mtmWorkflowRecordObjectLinkList.get(j)).getWorkflowRecordID())) {
          foundFlag = true;
          break;
        }
      }
      if (!foundFlag) {
        workflowRecordList.remove(i--);
      }
    }
    return workflowRecordList;
  }

  /**
   * replace the document content ,this function is used at save email archive
   *
   * @param document
   * @param contentStr
  */
  public void replaceDocPhysicalFileContent(DmsDocument document,String contentStr){
    InputStream dataStream = null;
    DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);

    try {
      DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
      String name = "";
      DmsVersion dmsVersion = new DmsVersion();
      Integer contentID = new Integer(0);
      dmsVersion = docRetrievalManager.getTopVersionByDocumentID(document.getID());
      contentID = dmsVersion.getContentID();

      DmsContent docContent = docRetrievalManager.getContentByContentID(contentID);
      if (!Utility.isEmpty(docContent.getExt())) {
        name = name + docContent.getExt();
      }
      name = TextUtility.getURLEncodeInUTF8(name);

      String converted = URLDecoder.decode(docContent.getConvertedName(), "UTF-8");


      try{
        //1.delete the older physical file,
        dmsContentManager.deleteDmsDocumentStoreContent(document,docContent);
        //2,new the replaced file
        dataStream = new DataInputStream(new ByteArrayInputStream(contentStr.getBytes("UTF-8")));
        dmsContentManager.writeDmsDocumentStoreContent(document,converted,dataStream);

      }catch(Exception e){
        throw new ApplicationException(DmsErrorConstant.PHYSICAL_FILE_NOT_FOUND,e);
      }
    } catch (Exception e) {
      log.error(e, e);
    } finally {
      try {
        dataStream.close();
      } catch (Exception ignore) {
      } finally {
        dataStream = null;
    }
    }

  }

  /**
   * get the document physical file content ,used at email archive get image servlet
   *
   * @param docID
   * @return
  */
  public InputStream getDocPhysicalFileContentByDocumentID(Integer docID){
    DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);

    InputStream dataStream = null;
    try {
      DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
      String name = "";

      DmsDocument document = docRetrievalManager.getDocument(docID);

      DmsVersion dmsVersion = new DmsVersion();
      Integer contentID = new Integer(0);
      dmsVersion = docRetrievalManager.getTopVersionByDocumentID(document.getID());
      contentID = dmsVersion.getContentID();

      DmsContent docContent = docRetrievalManager.getContentByContentID(contentID);
      if (!Utility.isEmpty(docContent.getExt())) {
        name = name + docContent.getExt();
      }

      name = TextUtility.getURLEncodeInUTF8(name);
      dataStream = dmsContentManager.readDmsDocumentStoreContent(document,docContent);

    } catch (Exception e) {
      log.error(e, e);
    } finally {
    }
    return dataStream;
  }

  /**
   * Copy sourceDocument to destinDocument.
   *
   * @param sourceDocument
   * @param destinDocument
   * @param newDmsDocument
   * @param validation
   * @param options
   * @return
   * @throws ApplicationException
   */
  public DmsDocument copyDocument(DmsDocument sourceDocument, DmsDocument destinDocument, DmsDocument newDmsDocument,
      DmsValidation validation, boolean[] options) throws ApplicationException {
    DmsDocument returnNewDmsDocument = null;
    MtmDocumentRelationshipDAObject mtmRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    MtmDocumentVersionDAObject mtmVersionDAO = new MtmDocumentVersionDAObject(sessionContainer, conn);
    DmsDocumentDetailDAObject docDetailDAO = new DmsDocumentDetailDAObject(sessionContainer, conn);
    // DmsDocumentIndexDAObject docIndexDAO = new
    // DmsDocumentIndexDAObject(sessionContainer, conn);
    DmsLocMasterDAObject locMasterDAO = new DmsLocMasterDAObject(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
    DmsContentDAObject dmsContentDAO = new DmsContentDAObject(sessionContainer, conn);
    DmsRootDAObject dmsRootDAObject = new DmsRootDAObject(sessionContainer, conn);
    AuditTrailDAObject auditDAO = new AuditTrailDAObject(sessionContainer, conn);
    DmsDocumentIndexDAObject indexDAO = new DmsDocumentIndexDAObject(sessionContainer, conn);
    //DmsDocumentIndexCacheDAObject indexCacheDAO = new DmsDocumentIndexCacheDAObject(this.sessionContainer, this.conn);
    DocumentValidateManager  docValidateManager  = new DocumentValidateManager(sessionContainer, conn);
    // DocumentValidateManager validator = new
    // DocumentValidateManager(sessionContainer, conn);
    // validator.validateNewShortcutAction(sourceDocument,destinDocument);

    try {
      List lstIndexCaches = new ArrayList();

      // step 1: get setting
      boolean optionWorkFlow = options[0];
      //boolean optionCopyFile = options[1];
      boolean optionCopyVersion = options[2];
      DmsRoot disDmsRoot = (DmsRoot) dmsRootDAObject.getObjectByID(destinDocument.getRootID());
      DmsRoot srcDmsRoot = (DmsRoot) dmsRootDAObject.getObjectByID(sourceDocument.getRootID());
      Integer disRootID = disDmsRoot.getID();
      String disRootType = disDmsRoot.getRootType();
      String disLocPath = ((DmsLocMaster) locMasterDAO.getObjectByID(disDmsRoot.getLocID())).getLocPath();
      String srcLocPath = ((DmsLocMaster) locMasterDAO.getObjectByID(srcDmsRoot.getLocID())).getLocPath();
      boolean copyPhysicalFile = !(disLocPath.equals(srcLocPath));
      DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);

      // step 2:
      List newDocumentIdList = new ArrayList();
      Map mapOldPIDToNewPID = new HashMap(); // record old id to new id mapping
      mapOldPIDToNewPID.put("D" + (sourceDocument.getParentID()), destinDocument.getID());
      List sortedIdList = validation.getLstIdAccept();

      int batchSize = 100; // handle 100 document everytime
      int batchIndex = 0; // loop times index
      int maxsize = sortedIdList.size();
      long startTime = System.currentTimeMillis();
      log.debug("copy size::::" + maxsize);
      while (true) {
        int index_start = (batchIndex++) * batchSize;
        if (index_start >= maxsize) {
          break;
        }
        int index_end = (index_start + batchSize) > maxsize ? maxsize : (index_start + batchSize);
        List batchDocumentIds = sortedIdList.subList(index_start, index_end);

        // step 2.1: DMS_DOCUMENT/DMS_DOCUMENT_DETAIL
        Map documents = dmsDocumentDAO.getMapByIDList(batchDocumentIds);
        DmsDocument tmpSrcDocument = null;
        DmsDocument tmpNewDocument = null;
        for (int i = 0; i < batchDocumentIds.size(); i++) {
          Integer srcID = (Integer) batchDocumentIds.get(i);
          tmpSrcDocument = (DmsDocument) documents.get(srcID);
          if (srcID.equals(sourceDocument.getID())) { // if it is copy root
                                                      // source, set new index
                                                      // and others' new
                                                      // attribute
            tmpSrcDocument.setDocumentName(newDmsDocument.getDocumentName());
            tmpSrcDocument.setReferenceNo(newDmsDocument.getReferenceNo());
            tmpSrcDocument.setDescription(newDmsDocument.getDescription());
            tmpSrcDocument.setUserDef1(newDmsDocument.getUserDef1());
            tmpSrcDocument.setUserDef2(newDmsDocument.getUserDef2());
            tmpSrcDocument.setUserDef3(newDmsDocument.getUserDef3());
            tmpSrcDocument.setUserDef4(newDmsDocument.getUserDef4());
            tmpSrcDocument.setUserDef5(newDmsDocument.getUserDef5());
            tmpSrcDocument.setUserDef6(newDmsDocument.getUserDef6());
            tmpSrcDocument.setUserDef7(newDmsDocument.getUserDef7());
            tmpSrcDocument.setUserDef8(newDmsDocument.getUserDef8());
            tmpSrcDocument.setUserDef9(newDmsDocument.getUserDef9());
            tmpSrcDocument.setUserDef10(newDmsDocument.getUserDef10());
          }
          if (DmsRoot.PERSONAL_ROOT.equals(disRootType)) {
            tmpSrcDocument.setEffectiveStartDate(new Timestamp(System.currentTimeMillis()));
            tmpSrcDocument.setEffectiveEndDate(null);
          }
          tmpSrcDocument.setParentID((Integer) mapOldPIDToNewPID.get("D" + (tmpSrcDocument.getParentID())));
          tmpSrcDocument.setRootID(disRootID);
          tmpSrcDocument.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
          tmpSrcDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);
          tmpSrcDocument.setOwnerID(sessionContainer.getUserRecordID());
          // joan.xiong update code for bug EIP-1224 by 2006/12/19
          // tmpSrcDocument.setReminderAmount(null);
          // tmpSrcDocument.setReminderType(null);
          if (!Utility.isEmpty(sourceDocument.getReminderAmount()) && !Utility.isEmpty(sourceDocument.getReminderType())) {
            tmpSrcDocument.setReminderAmount(sourceDocument.getReminderAmount());
            tmpSrcDocument.setReminderType(sourceDocument.getReminderType());
          }
          // joan.xiong update code end
          if (optionWorkFlow) {
            tmpSrcDocument.setRecordStatus(GlobalConstant.RECORD_PENDING);
          }

          if (DmsDocument.DOCUMENT_LINK.equals(tmpSrcDocument.getDocumentType())){
            docValidateManager.checkAndLockDuplicateNameCache(tmpSrcDocument);//add for change document name
          }

          tmpNewDocument = (DmsDocument) dmsDocumentDAO.insertOnly(tmpSrcDocument);
          if (srcID.equals(sourceDocument.getID())) {
            returnNewDmsDocument = tmpNewDocument;
            if (!Utility.isEmpty(newDmsDocument.getUserDefinedFieldID())) {
              List details = newDmsDocument.getDocumentDetails();
              for (int j = 0; j < details.size(); j++) {
                DmsDocumentDetail detail = (DmsDocumentDetail) details.get(j);
                detail.setDocumentID(tmpNewDocument.getID());
                docDetailDAO.insertOnly(detail);
              }
              if (!Utility.isEmpty(details)) {
                this.modifyDbIndex('I', details, tmpNewDocument.getID());
              }
            }
            lstIndexCaches.add(new DmsDocumentIndexCache(tmpNewDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_COPY,
                DmsDocumentIndexCache.ACTION_TYPE_UPDATE_ALL, srcID));
          } else {
            lstIndexCaches.add(new DmsDocumentIndexCache(tmpNewDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_COPY,
                DmsDocumentIndexCache.ACTION_TYPE_UPDATE_STANDARD, srcID));
          }
          mapOldPIDToNewPID.put("D" + srcID, tmpNewDocument.getID());
          newDocumentIdList.add(tmpNewDocument.getID());

          if (srcID.equals(sourceDocument.getID())) {
            try {
              AdapterMaster am = new AdapterMaster(sessionContainer, conn);
              am.call(UpdateAlert.DOCUMENT_TYPE, tmpNewDocument.getParentID(), UpdateAlert.CREATE_ACTION, tmpNewDocument.getDocumentName(),
                  null, null, null, tmpNewDocument.getID());
              am.release();
            } catch (Exception e) {
              log.error("Error when doing alert", e);
            }
          }
        }
        log.debug("copy step 1:::::" + (System.currentTimeMillis() - startTime));

        // step 2: DMS_DOCUMENT_DETAIL
        List lstDetails = docDetailDAO.getListByDocumentIDList(batchDocumentIds);
        DmsDocumentDetail detail = null;
        for (int i = 0; i < lstDetails.size(); i++) {
          detail = (DmsDocumentDetail) lstDetails.get(i);
          if (!sourceDocument.getID().equals(detail.getDocumentID())) { // source
                                                                        // root
                                                                        // has
                                                                        // new
                                                                        // attribute
            detail.setDocumentID((Integer) mapOldPIDToNewPID.get("D" + (detail.getDocumentID())));
            docDetailDAO.insertOnly(detail);
          }
        }
        log.debug("copy step 2:::::" + (System.currentTimeMillis() - startTime));

        // step 3: DMS_DOCUMENT_INDEX
        List indexs = indexDAO.getList(batchDocumentIds, GlobalConstant.RECORD_STATUS_ACTIVE);
        DmsDocumentIndex index = null;
        for (int i = 0; i < indexs.size(); i++) {
          index = (DmsDocumentIndex) indexs.get(i);
          if (!index.getDocumentID().equals(sourceDocument.getID())) {
            index.setDocumentID((Integer) mapOldPIDToNewPID.get("D" + (index.getDocumentID())));
            indexDAO.insertObject(index);
          }
        }

        // step 4: DMS_CONTENT
        List contents = null;
        if (optionCopyVersion) {
          contents = dmsContentDAO.getContentListByDocumentIDList(batchDocumentIds);
        } else {
          contents = dmsContentDAO.getContentListByVersionIDList(dmsVersionDAO.getTopVersionIDListByDocumentIDList(batchDocumentIds));
        }
        DmsContent tmpSrcContent = null;
        for (int i = 0; i < contents.size(); i++) {
          tmpSrcContent = (DmsContent) contents.get(i);
          if (copyPhysicalFile && (!Utility.isEmpty(tmpSrcContent.getExt()) || !Utility.isEmpty(tmpSrcContent.getContentType()))) {
            try {
              String convertName = tmpSrcContent.getConvertedName();
              InputStream dataStream = dmsContentManager.readDmsDocumentStoreContent(sourceDocument,tmpSrcContent);
              contentStoreHandler = dmsContentManager.writeDmsDocumentStoreContent(newDmsDocument,convertName,dataStream);
              Integer segmentNoInt = (Integer)contentStoreHandler.getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
              tmpSrcContent.setSegmentNO(segmentNoInt);
            } catch (Exception ex) {
              // addError(request, DmsErrorConstant.PHYSICAL_FILE_NOT_FOUND);
            }
          }

          Integer srcID = tmpSrcContent.getID();
          tmpSrcContent.setID(IDFactory.getInstance().getNextSequence("DMS_CONTENT"));
          tmpSrcContent = (DmsContent) dmsContentDAO.insertOnly(tmpSrcContent);
          mapOldPIDToNewPID.put("C" + srcID, tmpSrcContent.getID());
        }
        log.debug("copy step 4:::::" + (System.currentTimeMillis() - startTime));

        // step 5: DMS_VERSION
        List versions = null;
        if (optionCopyVersion) {
          versions = dmsVersionDAO.getVersionListByDocumentIDList(batchDocumentIds);
        } else {
          versions = dmsVersionDAO.getTopVersionListByDocumentIDList(batchDocumentIds);
        }
        DmsVersion tmpSrcVersion = null;
        for (int i = 0; i < versions.size(); i++) {
          tmpSrcVersion = (DmsVersion) versions.get(i);
          Integer docID = (Integer) mapOldPIDToNewPID.get("D" + (tmpSrcVersion.getDocumentID()));
          Integer conID = (Integer) mapOldPIDToNewPID.get("C" + (tmpSrcVersion.getContentID()));
          tmpSrcVersion.setDocumentID(docID);
          tmpSrcVersion.setContentID(conID);
          // joan.xiong update code for bug EIP-1191 by 2006/12/13
          tmpSrcVersion.setParentID(new Integer(0));
          if (i < 1) {
            tmpSrcVersion.setVersionLabel(StandardVersionLabelRule.ROOT_VERSION_LABEL);
          }
          // joan.xiong update code end
          tmpSrcVersion = (DmsVersion) dmsVersionDAO.insertOnly(tmpSrcVersion);

          MtmDocumentVersion mtmVersion = new MtmDocumentVersion();
          mtmVersion.setDocumentID(docID);
          mtmVersion.setVersionID(tmpSrcVersion.getID());
          mtmVersionDAO.insertOnly(mtmVersion);
        }

        // step 5.1: audit trail
        if (!DmsRoot.PERSONAL_ROOT.equals(disRootType)) {
          versions = dmsVersionDAO.getTopVersionListByDocumentIDList(batchDocumentIds);
          for (int i = 0; i < versions.size(); i++) {
            DmsVersion version = (DmsVersion) versions.get(i);
            Integer newDocID = (Integer) mapOldPIDToNewPID.get("D" + (version.getDocumentID()));
            String newVerNumber = optionCopyVersion ? version.getVersionNumber() : "1";
            // Update By Jim.Zhou 2006/07/24 Bug #5948
            // this.auditTrailDocument(auditDAO, version.getDocumentID(),
            // version.getVersionNumber(),
            // AuditTrailConstant.ACCESS_TYPE_COPY_FOLDER);
            // this.auditTrailDocument(auditDAO, newDocID, newVerNumber,
            // AuditTrailConstant.ACCESS_TYPE_COPY_CREATE);
            DmsDocument dmsDocument = (DmsDocument) dmsDocumentDAO.getObjectByID(version.getDocumentID());
            MtmDocumentRelationshipDAObject mtmRelationDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
            if (!DmsDocument.TIF_ANNOTATION_TYPE.equals(dmsDocument.getDocumentType())) {// barbin.
              // EIP-1296
              if (DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())) {
                this.auditTrailDocument(auditDAO, version.getDocumentID(), dmsDocument.getDocumentName(),
                    version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_COPY_FOLDER);
              } else if (DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
                setShortcutAuditTrail(dmsDocument.getID(), auditDAO, version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_COPY_SHORTCUT, GlobalConstant.RECORD_STATUS_ACTIVE);
              } else {
                this.auditTrailDocument(auditDAO, version.getDocumentID(), dmsDocument.getDocumentName(), version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_COPY);
              }
              if (DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
                setShortcutAuditTrail(dmsDocument.getID(), auditDAO, newVerNumber, AuditTrailConstant.ACCESS_TYPE_COPY_CREATE_SHORTCUT, GlobalConstant.RECORD_STATUS_ACTIVE);                                                                          // shortcut
              } else {
                this.auditTrailDocument(auditDAO, newDocID, dmsDocument.getDocumentName(), newVerNumber, AuditTrailConstant.ACCESS_TYPE_COPY_CREATE);
              }
              // Update End
            }
          }
        }
        log.debug("copy step 5:::::" + (System.currentTimeMillis() - startTime));

        // step 6:batch copy shortcut relations(MTM_DOCUMENT_RELATIONSHIP)
        List mtmRelationships = mtmRelationshipDAO.getListByRelatedDocumentIDList(batchDocumentIds);
        if (mtmRelationships != null && !mtmRelationships.isEmpty()) {
          MtmDocumentRelationship mtmRelationship = null;
          for (int i = 0; i < mtmRelationships.size(); i++) {
            mtmRelationship = (MtmDocumentRelationship) mtmRelationships.get(i);
            // if(DmsDocument.DOCUMENT_LINK.equals(tmpSrcDocument.getDocumentType())
            // &&
            // DmsDocument.DOCUMENT_LINK.equals(mtmRelationship.getRelationshipType())){
            // mtmRelationship.setRelatedDocumentID(tmpNewDocument.getID());
            // }else{
            mtmRelationship.setRelatedDocumentID((Integer) mapOldPIDToNewPID.get("D" + (mtmRelationship.getRelatedDocumentID())));
            // }
            mtmRelationshipDAO.insertOnly(mtmRelationship);
          }
        }
        log.debug("copy step 6:::::" + (System.currentTimeMillis() - startTime));

      }

      // step 7: add lucene index cache (DMS_DOCUMENT_INDEX_CACHE)
      if (!lstIndexCaches.isEmpty()) {
        this.insertIndexCaches(lstIndexCaches);
      }

      // commit copy process, step 7 need the commit data to handle operation
      try {
        conn.commit();
      } catch (Exception ex) {
        log.error(ex, ex);
      }
      // step 7: batch index on background thread, it would take much time.
      /*
       * IndexInBatchBackgroundThread indexBkThread = new IndexInBatchBackgroundThread(this.sessionContainer,
       * newDocumentIdList, GlobalConstant.OP_MODE_INSERT, null); indexBkThread.start();
       */
    } catch (ApplicationException ex) {
      throw ex;
    }
    return returnNewDmsDocument;
  }

  public void moveDocument(DmsDocument sourceDocument, DmsDocument distinDocument, DmsDocument newDmsDocument, DmsValidation validation,
      boolean isByWorkFlow) throws ApplicationException {
    DocumentRetrievalManager documentRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DmsLocMasterDAObject locMasterDAO = new DmsLocMasterDAObject(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
    DmsContentDAObject dmsContentDAO = new DmsContentDAObject(sessionContainer, conn);
    DmsRootDAObject dmsRootDAObject = new DmsRootDAObject(sessionContainer, conn);
    AuditTrailDAObject auditDAO = new AuditTrailDAObject(sessionContainer, conn);
    DocumentValidateManager  docValidateManager  = new DocumentValidateManager(sessionContainer, conn);
    DmsContentManager dmsContentManager = new DmsContentManager(sessionContainer, conn);

    try {
      List lstIndexCaches = new ArrayList();

      // step 1: load and get operation variable
      DmsRoot disDmsRoot = (DmsRoot) dmsRootDAObject.getObjectByID(distinDocument.getRootID());
      DmsRoot srcDmsRoot = (DmsRoot) dmsRootDAObject.getObjectByID(sourceDocument.getRootID());
      Integer disRootID = disDmsRoot.getID();
      //String disRootType = disDmsRoot.getRootType();
      String disLocPath = ((DmsLocMaster) locMasterDAO.getObjectByID(disDmsRoot.getLocID())).getLocPath();
      String srcLocPath = ((DmsLocMaster) locMasterDAO.getObjectByID(srcDmsRoot.getLocID())).getLocPath();
      boolean copyPhysicalFile = !(disLocPath.equals(srcLocPath));

      // step 2: move begin
      List sortedIdList = validation.getLstIdAccept();
      int batchSize = 100; // handle 100 document everytime
      int batchIndex = 0; // loop times index
      int maxsize = sortedIdList.size();

      while (true) {
        int index_start = (batchIndex++) * batchSize;
        if (index_start >= maxsize) {
          break;
        }
        int index_end = (index_start + batchSize) > maxsize ? maxsize : (index_start + batchSize);
        List batchDocumentIds = sortedIdList.subList(index_start, index_end);

        // step 2.1: move documents(dms_document) | alert target folder if
        // setted
        Map documents = dmsDocumentDAO.getMapByIDList(batchDocumentIds);
        DmsDocument tmpSrcDocument = null;
        DmsDocument tmpNewDocument = null;
        for (int i = 0; i < batchDocumentIds.size(); i++) {
          Integer srcID = (Integer) batchDocumentIds.get(i);
          tmpSrcDocument = (DmsDocument) documents.get(srcID);
          Integer orgiParentID = tmpSrcDocument.getParentID();
          // update all sessionctn permission string in cache
          PermissionManager.firePermissionChanged(GlobalConstant.OBJECT_TYPE_DOCUMENT, srcID);
          if (srcID.equals(sourceDocument.getID())) { // if it is copy root
                                                      // source, set new index
                                                      // and others' new
                                                      // attribute
            tmpSrcDocument.setDocumentName(newDmsDocument.getDocumentName());
            tmpSrcDocument.setReferenceNo(newDmsDocument.getReferenceNo());
            tmpSrcDocument.setDescription(newDmsDocument.getDescription());
            tmpSrcDocument.setParentID(distinDocument.getID());
            /*
             * joan.xiong add code for bug EIP-1112 by 2007/01/10
             */
            // check file if it is have default profile
            if (Utility.isEmpty(documentRetrievalManager.getDocumentDetailList(srcID))) {
              List docDetailList = documentRetrievalManager.getDocumentDetailList(distinDocument.getID());
              if (!Utility.isEmpty(docDetailList)) {
                List newDetailList = new ArrayList();
                DmsDocumentDetail docDetail = null;
                DmsDocumentDetail newDocDetail = null;
                for (int s = 0; s < docDetailList.size(); s++) {
                  docDetail = (DmsDocumentDetail) docDetailList.get(s);
                  docDetail.setDocumentID(tmpSrcDocument.getID());
                  newDocDetail = this.createDocumentDetail(docDetail);
                  newDetailList.add(newDocDetail);
                }
                List udfDetailList = documentRetrievalManager.getUDFDetailList(newDocDetail.getUserDefinedFieldID());
                newDmsDocument.setUserDefinedFieldID(newDocDetail.getUserDefinedFieldID());
                tmpSrcDocument.setUdfDetailList(udfDetailList);
                tmpSrcDocument.setDocumentDetails(docDetailList);
              }
            }
            /*
             * joan.xiong add code end
             */
          }
          if (DmsRoot.PERSONAL_ROOT.equals(disDmsRoot.getRootType())) {
            // tmpSrcDocument.setEffectiveStartDate(new
            // Timestamp(System.currentTimeMillis()));//Update By Jim Zhou
            // 2007/01/23 EIP-1495
            tmpSrcDocument.setEffectiveEndDate(null);
          }
          tmpSrcDocument.setRootID(disRootID);
          if (isByWorkFlow) {
            tmpSrcDocument.setRecordStatus(GlobalConstant.RECORD_PENDING);
          }

          if (DmsDocument.DOCUMENT_LINK.equals(tmpSrcDocument.getDocumentType())){
            docValidateManager.checkAndLockDuplicateNameCache(tmpSrcDocument);
          }

          tmpNewDocument = (DmsDocument) dmsDocumentDAO.updateObject(tmpSrcDocument);

          // alert target folder
          if (srcID.equals(sourceDocument.getID())) {
            try {
              AdapterMaster am = new AdapterMaster(sessionContainer, conn);
              am.call(UpdateAlert.DOCUMENT_TYPE, tmpNewDocument.getParentID(), UpdateAlert.CREATE_ACTION, tmpNewDocument.getDocumentName(),
                  null, null, null, tmpNewDocument.getID());
              am.call(UpdateAlert.DOCUMENT_TYPE, orgiParentID, UpdateAlert.UPDATE_ACTION, tmpNewDocument.getDocumentName(),
                  null, null, null, tmpNewDocument.getID());
              am.release();
            } catch (Exception e) {
              log.error("Error when doing alert", e);
            }
            lstIndexCaches.add(new DmsDocumentIndexCache(tmpNewDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_MOVE,
                DmsDocumentIndexCache.ACTION_TYPE_UPDATE_ALL, srcID));
          } else {
            lstIndexCaches.add(new DmsDocumentIndexCache(tmpNewDocument.getID(), DmsDocumentIndexCache.ACTION_MODE_MOVE,
                DmsDocumentIndexCache.ACTION_TYPE_UPDATE_STANDARD, srcID));
          }
          // if document is folder check the inner documents and send alert if have
          AdapterMaster am = new AdapterMaster(sessionContainer, conn);
          am.call(UpdateAlert.DOCUMENT_TYPE, tmpSrcDocument.getID(), UpdateAlert.UPDATE_ACTION, tmpSrcDocument.getDocumentName(),
              null, null, null, null);
          if(documentRetrievalManager.hasRelationship(tmpSrcDocument.getID(),null)){
            alertRelationDoc(tmpSrcDocument, am);
        }
          am.release();

        }

        // step 2.2: move physical file and set segment no to DMS_CONTENT
        if (copyPhysicalFile) {
          List contents = dmsContentDAO.getContentListByDocumentIDList(batchDocumentIds);
          DmsContent tmpSrcContent = null;
          for (int i = 0; i < contents.size(); i++) {
            tmpSrcContent = (DmsContent) contents.get(i);
            if (!Utility.isEmpty(tmpSrcContent.getExt()) || !Utility.isEmpty(tmpSrcContent.getContentType())) {
              try {
                String convertName = tmpSrcContent.getConvertedName();
                InputStream dataStream = dmsContentManager.readDmsDocumentStoreContent(sourceDocument,tmpSrcContent);
                contentStoreHandler = dmsContentManager.writeDmsDocumentStoreContent(newDmsDocument,convertName,dataStream);
                Integer segmentNoInt = (Integer)contentStoreHandler.getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
                tmpSrcContent.setSegmentNO(segmentNoInt);

              } catch (Exception ex) {
                // addError(request, DmsErrorConstant.PHYSICAL_FILE_NOT_FOUND);
              }
            }
            dmsContentDAO.updateOnly(tmpSrcContent);
          }
        }

        // step 2.3: audit trail
        // Update By Jim Zhou 2006/12/20 EIP-914
        // if (!DmsRoot.PERSONAL_ROOT.equals(disRootType)) {
        List versions = dmsVersionDAO.getTopVersionListByDocumentIDList(batchDocumentIds);
        for (int i = 0; i < versions.size(); i++) {
          DmsVersion version = (DmsVersion) versions.get(i);
          // Update By Jim.Zhou 2006/07/24 Bug #5948
          // this.auditTrailDocument(auditDAO, version.getDocumentID(),
          // version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_MOVE);
          DmsDocument dmsDocument = (DmsDocument) dmsDocumentDAO.getObjectByID(version.getDocumentID());
          if (!DmsDocument.TIF_ANNOTATION_TYPE.equals(dmsDocument.getDocumentType())) {// barbin
            // EIP-1296
            if (DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())) {
              this.auditTrailDocument(auditDAO, version.getDocumentID(), dmsDocument.getDocumentName(),
                  version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_MOVE_FOLDER);
            } else if (DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
              setShortcutAuditTrail(dmsDocument.getID(), auditDAO, version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_MOVE_SHORTCUT, GlobalConstant.RECORD_STATUS_ACTIVE);
            } else {
              this.auditTrailDocument(auditDAO, version.getDocumentID(), dmsDocument.getDocumentName(), version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_MOVE);
            }
          }
          // Update End
        }
      }
      // step 7: add lucene index cache (DMS_DOCUMENT_INDEX_CACHE)
      if (!lstIndexCaches.isEmpty()) {
        this.insertIndexCaches(lstIndexCaches);
      }

      // commit copy process, step 3 need the commit data to handle operation
      try {
        conn.commit();
      } catch (Exception ex) {
        log.error(ex, ex);
      }

      // step 3: remove the permission from cache
      PermissionManager permissionManager = sessionContainer.getPermissionManager();
      for (int i = 0; i < sortedIdList.size(); i++) {
        permissionManager.clearPermissionCache(GlobalConstant.OBJECT_TYPE_DOCUMENT, (Integer) sortedIdList.get(i));
      }

    } catch (ApplicationException ex) {
      throw new ApplicationException(ex);
    } catch (Exception e) {
      log.error(e, e);
    }
  }

  public void deleteDocument(DmsDocument sourceDocument, DmsValidation validation) throws ApplicationException {
    MtmDocumentRelationshipDAObject mtmRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    DmsObjectHomeFolderDAObject objectHomeFolderDAO = new DmsObjectHomeFolderDAObject(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
    DmsRootDAObject dmsRootDAO = new DmsRootDAObject(sessionContainer, conn);
    AdapterMaster alertMaster = new AdapterMaster(sessionContainer, conn);
    AuditTrailDAObject auditDAO = new AuditTrailDAObject(sessionContainer, conn);

    try {
      List lstIndexCaches = new ArrayList();

      // step 1: get rootType
      DmsRoot dmsRoot = (DmsRoot) dmsRootDAO.getObjectByID(sourceDocument.getRootID());
      String rootType = dmsRoot.getRootType();

      // step 2: loop and delete documents in batch
      List documentIds = validation.getLstIdAccept();
      Map mpIdToPid = validation.getMapIdToPid();
      int batchSize = 100; // handle 100 document everytime
      int batchIndex = 0; // loop times index
      int maxsize = documentIds.size();
      while (true) {
        // get loop index
        int index_start = (batchIndex++) * batchSize;
        if (index_start >= maxsize) {
          break;
        }
        int index_end = (index_start + batchSize) > maxsize ? maxsize : (index_start + batchSize);
        // get loop id list at this batch time
        List batchDocumentIds = documentIds.subList(index_start, index_end);

        // step 2.1: update DMS_DOCUMENT RECORD_STATUS
        dmsDocumentDAO.updateRecordStatusByIDList(batchDocumentIds, GlobalConstant.RECORD_STATUS_INACTIVE, this.sessionContainer
            .getUserRecordID());

        // step 2.2: update DMS_OBJECT_HOME_FOLDER RECORD_STATUS
        objectHomeFolderDAO.updateRecordStatusByDocumentIDList(batchDocumentIds, GlobalConstant.RECORD_STATUS_INACTIVE);

        // step 2.3: update MTM_DOCUMENT_RELATIONSHIP RECORD_STATUS
        mtmRelationshipDAO.updateStatusByDocumentIDList(batchDocumentIds, GlobalConstant.RECORD_STATUS_INACTIVE);

        // step : delete lucene index
        for (int i = 0; i < batchDocumentIds.size(); i++) {
          lstIndexCaches.add(new DmsDocumentIndexCache((Integer) batchDocumentIds.get(i), DmsDocumentIndexCache.ACTION_MODE_DELETE,
              DmsDocumentIndexCache.ACTION_TYPE_DELETE_SOFT, null));
        }

        // step 2.4: delete relationed document(related shortcut)
        List mtmRelationships = mtmRelationshipDAO.getListByDocumentIDList(batchDocumentIds);
        if (mtmRelationships != null && !mtmRelationships.isEmpty()) {
          List relationIds = new ArrayList();
          for (int i = 0; i < mtmRelationships.size(); i++) {
            MtmDocumentRelationship relationship = (MtmDocumentRelationship) mtmRelationships.get(i);
            if ("L".equals(relationship.getRelationshipType())) {
              relationIds.add(relationship.getRelatedDocumentID());
            }
          }
          if (!relationIds.isEmpty()) {
            dmsDocumentDAO.updateRecordStatusByIDList(relationIds, GlobalConstant.RECORD_STATUS_INACTIVE, this.sessionContainer
                .getUserRecordID());
            // delete shortcut lucene index
            for (int i = 0; i < relationIds.size(); i++) {
              lstIndexCaches.add(new DmsDocumentIndexCache((Integer) relationIds.get(i), DmsDocumentIndexCache.ACTION_MODE_DELETE,
                  DmsDocumentIndexCache.ACTION_TYPE_DELETE_SOFT, null));
            }
          }
        }

        // step 2.5: handle alert message(note:when documents has shortcut
        // relationship, what will happen?)
        List alertIdQueryList = new ArrayList();
        for (int i = 0; i < batchDocumentIds.size(); i++) {
          Integer id = (Integer) batchDocumentIds.get(i);
          alertIdQueryList.add(id);
          alertIdQueryList.add(mpIdToPid.get(id));
        }
        List alertDocumentList = dmsDocumentDAO.getAlertListByIDList(alertIdQueryList, UpdateAlert.DELETE_ACTION,
            GlobalConstant.RECORD_STATUS_ACTIVE);
        if (!alertDocumentList.isEmpty()) {
          List alertIDList = new ArrayList();
          for (int j = 0; j < alertDocumentList.size(); j++) {
            DmsDocument doc = (DmsDocument) alertDocumentList.get(j);
            alertIDList.add(doc.getID());
          }
          for (int i = 0; i < batchDocumentIds.size(); i++) {
            try {
              Integer id = (Integer) batchDocumentIds.get(i);
              Integer pid = (Integer) mpIdToPid.get(id);
              if (alertIDList.contains(id) || alertIDList.contains(pid)) {
                DmsDocument alertDocument = (DmsDocument) dmsDocumentDAO.getObjectByID(id);
                if (alertIDList.contains(id)) {
                  alertMaster.call(UpdateAlert.DOCUMENT_TYPE, alertDocument.getID(), UpdateAlert.DELETE_ACTION, alertDocument
                      .getDocumentName(), null, null, null);
                }
                if (alertIDList.contains(pid)) {
                  alertMaster.call(UpdateAlert.DOCUMENT_TYPE, pid, UpdateAlert.DELETE_ACTION, alertDocument.getDocumentName(), null, null,
                      null, alertDocument.getID());
                }
              }
            } catch (Exception e) {
              log.error(e, e);
            }
          }
        }

        // step 2.6: audit trail
        if (!DmsRoot.PERSONAL_ROOT.equals(rootType)) {
          List versions = dmsVersionDAO.getTopVersionListByDocumentIDList(batchDocumentIds);
          for (int i = 0; i < versions.size(); i++) {
            DmsVersion version = (DmsVersion) versions.get(i);
            // Update By Jim.Zhou 2006/07/24 Bug #5948
            // auditTrailDocument(auditDAO, version.getDocumentID(),
            // version.getVersionNumber(),
            // AuditTrailConstant.ACCESS_TYPE_DELETE);
            DmsDocument dmsDocument = (DmsDocument) dmsDocumentDAO.getObjectByID(version.getDocumentID());
            if (!DmsDocument.TIF_ANNOTATION_TYPE.equals(dmsDocument.getDocumentType())) {// barin
              // EIP-1296
              if (DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())) {
                auditTrailDocument(auditDAO, version.getDocumentID(), dmsDocument.getDocumentName(),
                    version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_DELETE_FOLDER);
              } else if (DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
                setShortcutAuditTrail(dmsDocument.getID(), auditDAO, version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_DELETE_SHORTCUT, GlobalConstant.RECORD_STATUS_INACTIVE);
              } else {
                auditTrailDocument(auditDAO, version.getDocumentID(), dmsDocument.getDocumentName(), version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_DELETE);
              }
            }
          }
        }
      }

      // if it is root folder, then delete related dms_root record
      if (new Integer("0").equals(sourceDocument.getParentID()) && validation.isSuccess()) {
        dmsRootDAO.deleteObjectByID(sourceDocument.getRootID());
      }

      // step : add lucene index caches (DMS_DOCUMENT_INDEX_CACHE)
      if (!lstIndexCaches.isEmpty()) {
        this.insertIndexCaches(lstIndexCaches);
      }

      // step 3: commit delete
      try {
        conn.commit();
      } catch (Exception ex) {
        log.error(ex, ex);
      }
    } catch (ApplicationException ex) {
      throw ex;
    }
  }

  public void deleteDocument2(DmsDocument sourceDocument,String[] exSelectedIDs, DmsValidation validation) throws ApplicationException {
    MtmDocumentRelationshipDAObject mtmRelationshipDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    DmsObjectHomeFolderDAObject objectHomeFolderDAO = new DmsObjectHomeFolderDAObject(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionContainer, conn);
    DmsRootDAObject dmsRootDAO = new DmsRootDAObject(sessionContainer, conn);
    AdapterMaster alertMaster = new AdapterMaster(sessionContainer, conn);
    AuditTrailDAObject auditDAO = new AuditTrailDAObject(sessionContainer, conn);

    try {
      List lstIndexCaches = new ArrayList();

      // step 1: get rootType
      DmsRoot dmsRoot = (DmsRoot) dmsRootDAO.getObjectByID(sourceDocument.getRootID());
      String rootType = dmsRoot.getRootType();

      // step 2: loop and delete documents in batch
      List documentIds = validation.getLstIdAccept();
      Map mpIdToPid = validation.getMapIdToPid();
      int batchSize = 100; // handle 100 document everytime
      int batchIndex = 0; // loop times index
      int maxsize = documentIds.size();
      while (true) {
        // get loop index
        int index_start = (batchIndex++) * batchSize;
        if (index_start >= maxsize) {
          break;
        }
        int index_end = (index_start + batchSize) > maxsize ? maxsize : (index_start + batchSize);
        // get loop id list at this batch time

        List batchDocumentIds = documentIds.subList(index_start, index_end);

        batchDocumentIds=excludeNonSelect(batchDocumentIds,sourceDocument.getID(),exSelectedIDs,dmsDocumentDAO);
        if(Utility.isEmpty(batchDocumentIds)) {
          break;
        }

        // step 2.1: update DMS_DOCUMENT RECORD_STATUS
        dmsDocumentDAO.updateRecordStatusByIDList(batchDocumentIds, GlobalConstant.RECORD_STATUS_INACTIVE, this.sessionContainer
            .getUserRecordID());

        // step 2.2: update DMS_OBJECT_HOME_FOLDER RECORD_STATUS
        objectHomeFolderDAO.updateRecordStatusByDocumentIDList(batchDocumentIds, GlobalConstant.RECORD_STATUS_INACTIVE);

        // step 2.3: update MTM_DOCUMENT_RELATIONSHIP RECORD_STATUS
        mtmRelationshipDAO.updateStatusByDocumentIDList(batchDocumentIds, GlobalConstant.RECORD_STATUS_INACTIVE);

        // step : delete lucene index
        for (int i = 0; i < batchDocumentIds.size(); i++) {
          lstIndexCaches.add(new DmsDocumentIndexCache((Integer) batchDocumentIds.get(i), DmsDocumentIndexCache.ACTION_MODE_DELETE,
              DmsDocumentIndexCache.ACTION_TYPE_DELETE_SOFT, null));
        }

        // step 2.4: delete relationed document(related shortcut)
        List mtmRelationships = mtmRelationshipDAO.getListByDocumentIDList(batchDocumentIds);
        if (mtmRelationships != null && !mtmRelationships.isEmpty()) {
          List relationIds = new ArrayList();
          for (int i = 0; i < mtmRelationships.size(); i++) {
            MtmDocumentRelationship relationship = (MtmDocumentRelationship) mtmRelationships.get(i);
            if ("L".equals(relationship.getRelationshipType())) {
              relationIds.add(relationship.getRelatedDocumentID());
            }
          }
          if (!relationIds.isEmpty()) {
            for (int i = 0; i < relationIds.size(); i++) {
              DmsDocument tempRelationDocument = (DmsDocument)dmsDocumentDAO.getDocumentByID((Integer)relationIds.get(i), null);
              if (GlobalConstant.RECORD_STATUS_ACTIVE.equals(tempRelationDocument.getRecordStatus())) {
                ArrayList tempIDs = new ArrayList();
                tempIDs.add(tempRelationDocument.getID());
                dmsDocumentDAO.updateRecordStatusByIDList(tempIDs, GlobalConstant.RECORD_STATUS_INACTIVE, this.sessionContainer
                    .getUserRecordID());
                // delete shortcut lucene index
                lstIndexCaches.add(new DmsDocumentIndexCache((Integer) relationIds.get(i), DmsDocumentIndexCache.ACTION_MODE_DELETE,
                    DmsDocumentIndexCache.ACTION_TYPE_DELETE_SOFT, null));
              }
            }
          }
        }

        // step 2.5: handle alert message(note:when documents has shortcut
        // relationship, what will happen?)
        List alertIdQueryList = new ArrayList();
        for (int i = 0; i < batchDocumentIds.size(); i++) {
          Integer id = (Integer) batchDocumentIds.get(i);
          alertIdQueryList.add(id);
          alertIdQueryList.add(mpIdToPid.get(id));
        }
        List alertDocumentList = dmsDocumentDAO.getAlertListByIDList(alertIdQueryList, UpdateAlert.DELETE_ACTION,
            GlobalConstant.RECORD_STATUS_ACTIVE);
        if (!alertDocumentList.isEmpty()) {
          List alertIDList = new ArrayList();
          for (int j = 0; j < alertDocumentList.size(); j++) {
            DmsDocument doc = (DmsDocument) alertDocumentList.get(j);
            alertIDList.add(doc.getID());
          }
          for (int i = 0; i < batchDocumentIds.size(); i++) {
            try {
              Integer id = (Integer) batchDocumentIds.get(i);
              Integer pid = (Integer) mpIdToPid.get(id);
              if (alertIDList.contains(id) || alertIDList.contains(pid)) {
                DmsDocument alertDocument = (DmsDocument) dmsDocumentDAO.getObjectByID(id);
                if (alertIDList.contains(id)) {
                  alertMaster.call(UpdateAlert.DOCUMENT_TYPE, alertDocument.getID(), UpdateAlert.DELETE_ACTION, alertDocument
                      .getDocumentName(), null, null, null);
                }
                if (alertIDList.contains(pid)) {
                  alertMaster.call(UpdateAlert.DOCUMENT_TYPE, pid, UpdateAlert.DELETE_ACTION, alertDocument.getDocumentName(), null, null,
                      null, alertDocument.getID());
                }
              }
            } catch (Exception e) {
              log.error(e, e);
            }
          }
        }

        // step 2.6: audit trail
        if (!DmsRoot.PERSONAL_ROOT.equals(rootType)) {
          List versions = dmsVersionDAO.getTopVersionListByDocumentIDList(batchDocumentIds);
          for (int i = 0; i < versions.size(); i++) {
            DmsVersion version = (DmsVersion) versions.get(i);
            DmsDocument dmsDocument = (DmsDocument) dmsDocumentDAO.getObjectByID(version.getDocumentID());
            if (!DmsDocument.TIF_ANNOTATION_TYPE.equals(dmsDocument.getDocumentType())) {// barin
              // EIP-1296
              if (DmsDocument.FOLDER_TYPE.equals(dmsDocument.getDocumentType())) {
                auditTrailDocument(auditDAO, version.getDocumentID(), dmsDocument.getDocumentName(),
                    version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_DELETE_FOLDER);
              } else if (DmsDocument.DOCUMENT_LINK.equals(dmsDocument.getDocumentType())) {
                setShortcutAuditTrail(dmsDocument.getID(), auditDAO, version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_DELETE_SHORTCUT, GlobalConstant.RECORD_STATUS_INACTIVE); 
              } else {
                auditTrailDocument(auditDAO, version.getDocumentID(), dmsDocument.getDocumentName(), version.getVersionNumber(), AuditTrailConstant.ACCESS_TYPE_DELETE);
              }
            }
          }
        }
      }

      // if it is root folder, then delete related dms_root record
      if (new Integer("0").equals(sourceDocument.getParentID()) && validation.isSuccess()) {
        dmsRootDAO.deleteObjectByID(sourceDocument.getRootID());
      }

      // step : add lucene index caches (DMS_DOCUMENT_INDEX_CACHE)
      if (!lstIndexCaches.isEmpty()) {
        this.insertIndexCaches(lstIndexCaches);
      }

      // step 3: commit delete
      try {
        conn.commit();
      } catch (Exception ex) {
        log.error(ex, ex);
      }
    } catch (ApplicationException ex) {
      throw ex;
    }
  }
  
  /**
   * exclude no select for document have shout cut 
   * @param batchDocumentIds
   * @param sourceId
   * @param exSelectedIDs
   * @param dmsDocumentDAO
   * @return
   * @throws ApplicationException
   */
  private List excludeNonSelect(List batchDocumentIds,Integer sourceId,String[] exSelectedIDs,DmsDocumentDAObject dmsDocumentDAO) throws ApplicationException{
    if(exSelectedIDs!=null && exSelectedIDs.length>0){
      int l=exSelectedIDs.length;
      for(int i=0;i<l;i++){
        Integer id=Integer.valueOf(exSelectedIDs[i]);
        recursionRemoveId(batchDocumentIds,sourceId,id,dmsDocumentDAO);
      }
    }
    return batchDocumentIds;
  }
  
  
  /**
   * up recursion get document Id
   * @param batchDocumentIds
   * @param sourceId
   * @param id
   * @param dmsDocumentDAO
   * @throws ApplicationException
   */
  private void recursionRemoveId(List batchDocumentIds,Integer sourceId,Integer id,DmsDocumentDAObject dmsDocumentDAO) throws ApplicationException{
    batchDocumentIds.remove(id);
    DmsDocument tempDoc=(DmsDocument)dmsDocumentDAO.getObjectByID(id);
    Integer parentId=tempDoc.getParentID();
    if(parentId.intValue()!=sourceId.intValue() && parentId.intValue()>sourceId.intValue()){
      batchDocumentIds.remove(parentId);
      recursionRemoveId(batchDocumentIds,sourceId,parentId,dmsDocumentDAO);
    }else if(parentId.intValue()==sourceId.intValue()){
      batchDocumentIds.remove(sourceId);
    }
  }
  
  private void setShortcutAuditTrail(Integer docID, AuditTrailDAObject auditDAO, String versionNumber, String accessType, String recordStatus) throws ApplicationException{
    MtmDocumentRelationshipDAObject mtmRelationDAO = new MtmDocumentRelationshipDAObject(sessionContainer, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(sessionContainer, conn);
    
    List mtmRelationList = mtmRelationDAO.getDocIDByRelatedDocID(docID, DmsDocument.DOCUMENT_LINK, recordStatus);
    Integer objID = new Integer(-1); //-1 means the related file is NULL.
    if (!mtmRelationList.isEmpty()){
      objID = (Integer) mtmRelationList.get(0);
    }
    
    DmsDocument dmsDocument = (DmsDocument) dmsDocumentDAO.getObjectByID(objID);
    String documentName = dmsDocument == null ? "" : dmsDocument.getDocumentName(); 
    this.auditTrailDocument(auditDAO, objID, documentName, versionNumber, accessType);
  }

  public void auditTrailDocument(AuditTrailDAObject auditDAO, Integer objectID, String objectName, String versionNumber, String accessType)
      throws ApplicationException {
    AuditTrail audit = new AuditTrail();
    audit.setObjectType(GlobalConstant.OBJECT_TYPE_DOCUMENT);
    audit.setObjectID(objectID);
    audit.setObjectName(objectName);
    audit.setVersionNumber(versionNumber);
    audit.setAccessType(accessType);
    audit.setSessionID(sessionContainer.getSessionID());
    audit.setAccessorID(sessionContainer.getUserRecordID());
    audit.setIpAddress(sessionContainer.getUserIPAddress());
    auditDAO.insertObject(audit);
  }

  public void indexLUCENE(DmsDocumentIndexCache indexCache, DmsDocument dmsDocument, DmsContent dmsContent, InputStream data)
      throws ApplicationException {
    try {
      boolean runImmediately = SystemParameterFactory.getSystemParameterBoolean(SystemParameterConstant.DMS_INDEX_RUN_IMMEDIATELY);
      //if is from parascan, full text data need to index immediately.
      if (DmsDocumentIndexCache.ACTION_TYPE_RUN_IMMEDIATELY.equals(indexCache.getActionType())) {
        runImmediately = true;
      }
      if (!runImmediately) {
        DmsDocumentIndexCacheDAObject indexCacheDAO = new DmsDocumentIndexCacheDAObject(this.sessionContainer, this.conn);
        indexCacheDAO.insertObject(indexCache);
        indexCacheDAO = null;
      }else {
        //delete index lucene immediately.
        IndexManager indexManager = null;
        try {
          indexManager = new IndexManager(this.sessionContainer, this.conn);

          if (DmsDocumentIndexCache.ACTION_MODE_DELETE.equals(indexCache.getActionMode())) {
            if (DmsDocumentIndexCache.ACTION_TYPE_DELETE_SOFT.equals(indexCache.getActionType())) {
              Document doc = indexManager.queryDocument(indexCache.getDmsDocumentID());
              if (doc!=null) {
                doc = indexManager.resetDocument(doc, new String[] { FieldNames.RECORD_STATUS },
                    new String[] { GlobalConstant.RECORD_STATUS_INACTIVE });
              }
              indexManager.deleteDmsDocument(indexCache.getDmsDocumentID());
              indexManager.addDocument(doc);
            }else if (DmsDocumentIndexCache.ACTION_TYPE_DELETE_HARD.equals(indexCache.getActionType())) {
              indexManager.deleteDmsDocument(indexCache.getDmsDocumentID());
            }
          }else if (DmsDocumentIndexCache.ACTION_MODE_INSERT.equals(indexCache.getActionMode())) {
            if (DmsDocumentIndexCache.ACTION_TYPE_RUN_IMMEDIATELY.equals(indexCache.getActionType())) {
              indexManager.addDmsDocument(dmsDocument, dmsContent, data, dmsDocument.getDocumentDetails());
            }else if (DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_DATABASE.equals(indexCache.getActionType())) {
              indexManager.addDmsDocument(dmsDocument);
            }else if (DmsDocumentIndexCache.ACTION_TYPE_INSERT_BY_PARAM.equals(indexCache.getActionType())) {
              indexManager.addDmsDocument(dmsDocument, dmsContent, data, dmsDocument.getDocumentDetails());
            }
          }else if (DmsDocumentIndexCache.ACTION_MODE_UPDATE.equals(indexCache.getActionMode())) {
            Document doc = indexManager.queryDocument(indexCache.getDmsDocumentID());
            if (doc!=null) {
              if (DmsDocumentIndexCache.ACTION_TYPE_UPDATE_ALL.equals(indexCache.getActionType())) {
                doc = indexManager.resetDocumentStandardFields(doc, dmsDocument);
                doc = indexManager.resetDocumentDDFIndexFields(doc, dmsDocument);
                doc = indexManager.resetDocumentUDFIndexFields(doc, dmsDocument.getDocumentDetails());
              }else if (DmsDocumentIndexCache.ACTION_TYPE_UPDATE_STANDARD.equals(indexCache.getActionType())) {
                doc = indexManager.resetDocumentStandardFields(doc, dmsDocument);
              }else if (DmsDocumentIndexCache.ACTION_TYPE_UPDATE_NAME.equals(indexCache.getActionType())) {
                doc = indexManager.resetDocument(doc, new String[] { FieldNames.DOCUMENT_NAME, FieldNames.DOCUMENT_NAME_SORT },
                    new String[] { dmsDocument.getDocumentName(), dmsDocument.getDocumentName() });
              }
              indexManager.deleteDmsDocument(indexCache.getDmsDocumentID());
              indexManager.addDocument(doc);
            }
          }else if (DmsDocumentIndexCache.ACTION_MODE_COPY.equals(indexCache.getActionMode())) {
            Document doc = indexManager.queryDocument(indexCache.getSourceDocumentID());
            if (doc!=null) {
              if (DmsDocumentIndexCache.ACTION_TYPE_UPDATE_ALL.equals(indexCache.getActionType())) {
                doc = indexManager.resetDocumentStandardFields(doc, dmsDocument, null);
                doc = indexManager.resetDocumentDDFIndexFields(doc, dmsDocument);
                doc = indexManager.resetDocumentUDFIndexFields(doc, dmsDocument.getDocumentDetails());
              }else if (DmsDocumentIndexCache.ACTION_TYPE_UPDATE_STANDARD.equals(indexCache.getActionType())) {
                doc = indexManager.resetDocumentStandardFields(doc, dmsDocument, null);
              }
              indexManager.addDocument(doc);
            }
          }else if (DmsDocumentIndexCache.ACTION_MODE_MOVE.equals(indexCache.getActionMode())) {
            Document doc = indexManager.queryDocument(indexCache.getSourceDocumentID());
            if (doc!=null) {
              if (DmsDocumentIndexCache.ACTION_TYPE_UPDATE_ALL.equals(indexCache.getActionType())) {
                doc = indexManager.resetDocumentStandardFields(doc, dmsDocument, null);
                doc = indexManager.resetDocumentDDFIndexFields(doc, dmsDocument);
                doc = indexManager.resetDocumentUDFIndexFields(doc, dmsDocument.getDocumentDetails());
              }else if (DmsDocumentIndexCache.ACTION_TYPE_UPDATE_STANDARD.equals(indexCache.getActionType())) {
                doc = indexManager.resetDocumentStandardFields(doc, dmsDocument, null);
              }
              indexManager.deleteDmsDocument(indexCache.getSourceDocumentID());
              indexManager.addDocument(doc);
            }
          }else if (DmsDocumentIndexCache.ACTION_MODE_RESTORE.equals(indexCache.getActionMode())) {
            Document doc = indexManager.queryDocument(indexCache.getDmsDocumentID());
            if (doc!=null) {
              doc = indexManager.resetDocument(doc, new String[] { FieldNames.RECORD_STATUS },
                  new String[] { GlobalConstant.RECORD_STATUS_ACTIVE });
              indexManager.deleteDmsDocument(indexCache.getDmsDocumentID());
              indexManager.addDocument(doc);
            }
          }else if (DmsDocumentIndexCache.ACTION_MODE_CHECKIN.equals(indexCache.getActionMode())) {
            Document doc = indexManager.queryDocument(indexCache.getDmsDocumentID());
            if (doc!=null) {
              doc = indexManager.resetDocumentStandardFields(doc, dmsDocument, null);
              doc = indexManager.resetDocumentContent(doc, data, dmsContent.getExt());
              indexManager.deleteDmsDocument(indexCache.getDmsDocumentID());
              indexManager.addDocument(doc);
            }else {
              indexManager.addDmsDocument(dmsDocument, dmsContent, data, dmsDocument.getDocumentDetails());
            }
          }
        }catch (ApplicationException ex) {
          throw ex;
        }catch (Exception ex) {
          throw new ApplicationException(ErrorConstant.INDEX_UNEXPECTED_EXCEPTION, ex, ex.toString());
        }finally {
          indexManager.close();
        }
      }
    }catch (Exception ex) {
      log.error(ex, ex);
    }finally {
      try {
        data.close();
      } catch (Exception ex) {
      } finally {
        data = null;
    }
  }
  }

  /**
   * Add record to dms_document_index_cache. An background lucene index thread would run and use these data.
   *
   * @param lstIndexCaches
   * @throws ApplicationException
   */
  private void insertIndexCaches(List lstIndexCaches) throws ApplicationException {
    DmsDocumentIndexCacheDAObject indexCacheDAO = new DmsDocumentIndexCacheDAObject(this.sessionContainer, this.conn);
    for (int i=0; i<lstIndexCaches.size(); i++) {
      indexCacheDAO.insertObject((DmsDocumentIndexCache)lstIndexCaches.get(i));
    }
    indexCacheDAO = null;
  }

  /**
   * Add record to dms_document_index. This table data would be used at advanced search progress. This method is prepare
   * for insert/update doucment operation.
   *
   * @param mode
   * @param documentDetails
   * @param dmsDocumentID
   * @throws ApplicationException
   */
  private void modifyDbIndex(char mode, List documentDetails, Integer dmsDocumentID) throws ApplicationException {
    DmsDocumentIndexDAObject dmsDocumentIndexDAO = new DmsDocumentIndexDAObject(sessionContainer, conn);

    DmsDocumentIndex index = null;
    switch (mode) {
      case 'I':
        index = this.convertDetailsToIndex(documentDetails, dmsDocumentID);
        if (index!=null) {
          dmsDocumentIndexDAO.insertObject(index);
        }
        break;
      case 'U':
        index = this.convertDetailsToIndex(documentDetails, dmsDocumentID);
        dmsDocumentIndexDAO.deleteByDocID(dmsDocumentID);
      if (index != null) {
        dmsDocumentIndexDAO.insertObject(index);
      }
        break;
    }
  }

  private DmsDocumentIndex convertDetailsToIndex(List details, Integer dmsDocumentID) {
    if (details!=null) {
    try{
    DocumentRetrievalManager documentRetrievalManager = new DocumentRetrievalManager(sessionContainer,conn);
      details  =  documentRetrievalManager.sortDocDetailList(details);
    }catch(Exception e){
      log.error(e, e);
    }
      DmsDocumentIndex index = new DmsDocumentIndex();
      index.setDocumentID(dmsDocumentID);
      for (int i = 0; i <details.size(); i++) {
        DmsDocumentDetail detail = (DmsDocumentDetail)details.get(i);
        if (i == 0) {
          index.setUserDefinedFieldID(detail.getUserDefinedFieldID());
        }
        String value = null;
        if (!Utility.isEmpty(detail.getFieldValue())) {
          value = detail.getFieldValue();
        }else if (!Utility.isEmpty(detail.getNumericValue())) {
          value = detail.getNumericValue().toString();
        }else if (!Utility.isEmpty(detail.getDateValue())) {
          value = TextUtility.formatTimestampToIndex(detail.getDateValue());
        }
        String[] aryValue = new String[]{value};
        try {
          Method setIndex = index.getClass().getMethod("setIndex" + (i+1), new Class[] {String.class});
          setIndex.invoke(index, aryValue);
        }catch (Exception ex) {
          log.error(ex, ex);
        }
      } //end for
      return index;
    }else {
      return null;
    }
  }

  /**
   * create a new shortcut in DMS. joan.xiong add
   *
   * @param sourceDoc
   * @param targetDoc
   * @param newDoc
   * @return
   * @throws ApplicationException
   */
  public DmsDocument createNewShortcut(DmsDocument sourceDoc, DmsDocument targetDoc, DmsDocument newDoc) throws ApplicationException {
    DocumentValidateManager dmsValidateManager = new DocumentValidateManager(sessionContainer, conn);
    dmsValidateManager.validateNewShortcutAction(sourceDoc, targetDoc);
    return this.createDocument(newDoc, null, false, null);
  }





}